我有一個數據庫幫助程序類和三個數據源類,用於同一數據庫中的三個表。 通過AsyncTasks可以在很多地方訪問數據庫。我遇到了這個「嘗試重新打開一個已經關閉的對象......」的問題,我搜索了一下,發現dbhelper.getReadableDatabase()
爲已經打開的連接返回相同的對象。我猜想這個問題一定是由於兩個線程同時執行操作,其中一個線程完成其任務並調用close()
連接關閉,並且正在運行的線程拋出此異常。 因此,爲了避免close()
我寫了以下兩種方法:嘗試重新打開已關閉的對象
public static synchronized void newOpenRequest() {
requestsOpen++;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
}
public static synchronized boolean canClose() {
requestsOpen--;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
if(requestsOpen == 0)
return true;
return false;
}
在所有這三個數據源類的,當我做它在以下方式:
private void openRead() {
database = dbhelper.getReadableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void openWrite() {
database = dbhelper.getWritableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void close() {
if (DBHelper.canClose()) {
dbhelper.close();
Util.debuglog(TAG, "Database closed.");
}
}
我logcat的輸出如下:
因此,如黑色突出顯示矩形,共openRequests
爲0,所以數據庫關閉,正常,但如紅色矩形突出顯示, 首先openRequests
爲0,這樣的時間只有數據庫應該關閉,但(我的猜測)發生了什麼是canClose()
返回爲一個線程爲true ,並且在致電dbhelper.close();
之前調用另一個線程open()
(因爲openRequests = 1在關閉之前在LogCat上),然後調用第一個線程的close()
給另一個正在運行的線程造成麻煩。
所以尋找解決方案來避免這種併發訪問問題。 謝謝。
是'requestsOpen'一個'volatile'場? – 2014-10-10 14:18:12
@PedroOliveira不,但我猜想使用同步方法會在這裏產生volatile。 – 2014-10-10 16:43:27
我不確定。但由於您可以同時調用close和open(因爲它們是相互獨立同步的),所以可以通過不同的任務同時更改該值。你爲什麼不保存一個以單例打開的數據庫實例並從異步任務中訪問它? – 2014-10-10 16:45:34