我有一个数据库帮助程序类和三个数据源类,用于同一数据库中的三个表。 通过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