Rx java 关闭sqlite数据库时发生死锁

Rx java 关闭sqlite数据库时发生死锁,rx-java,deadlock,android-room,sqlcipher,commonsware-cwac,Rx Java,Deadlock,Android Room,Sqlcipher,Commonsware Cwac,我正在调查我项目中的偶然事件。当后台有很多对数据库的请求,用户单击按钮,数据库作为注销的一部分被关闭时,就会发生这种情况。我用的是saferoom和rx-java2 以下是测试项目中的一些代码,我试图在其上复制该问题(复制了约30%的时间): 如您所见,为了模拟这个问题,我尝试在循环中访问数据库,同时关闭数据库。即使我在关闭前处理了写链,死锁还是会发生,应用程序也会冻结 我还尝试分析线程转储: "main" prio=5 tid=1 Waiting | group="main" sCount

我正在调查我项目中的偶然事件。当后台有很多对数据库的请求,用户单击按钮,数据库作为注销的一部分被关闭时,就会发生这种情况。我用的是saferoom和rx-java2

以下是测试项目中的一些代码,我试图在其上复制该问题(复制了约30%的时间):

如您所见,为了模拟这个问题,我尝试在循环中访问数据库,同时关闭数据库。即使我在关闭前处理了写链,死锁还是会发生,应用程序也会冻结

我还尝试分析线程转储:

"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x727565f0 self=0x7b42cbea00
  | sysTid=24431 nice=-10 cgrp=default sched=0/0 handle=0x7bc78e99a8
  | state=S schedstat=( 3718987857 647207377 6247 ) utm=336 stm=34 core=3 HZ=100
  | stack=0x7fd4c9a000-0x7fd4c9c000 stackSize=8MB
  | held mutexes=
  at java.lang.Object.wait(Native method)
  - waiting on <0x017bb93d> (a java.lang.Object)
  at java.lang.Thread.parkFor$(Thread.java:2137)
  - locked <0x017bb93d> (a java.lang.Object)
  at sun.misc.Unsafe.park(Unsafe.java:358)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:868)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:900)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1223)
  at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:225)
  at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:286)
  at net.sqlcipher.database.SQLiteDatabase.lock(SQLiteDatabase.java:553)
  at net.sqlcipher.database.SQLiteDatabase.close(SQLiteDatabase.java:1284)
  at net.sqlcipher.database.SQLiteOpenHelper.close(SQLiteOpenHelper.java:272)
  - locked <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1)
  at com.commonsware.cwac.saferoom.Helper$OpenHelper.close(Helper.java:202)
  - locked <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1)
  at com.commonsware.cwac.saferoom.Helper.close(Helper.java:146)
  at androidx.room.RoomDatabase.close(RoomDatabase.java:189)
  at com.company.deadlocktest.MainActivity$onCreate$1.onClick(MainActivity.kt:38)
  at android.view.View.performClick(View.java:6294)
  at android.view.View$PerformClick.run(View.java:24770)
  at android.os.Handler.handleCallback(Handler.java:790)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:164)
  at android.app.ActivityThread.main(ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)


"RxComputationThreadPool-1" daemon prio=5 tid=15 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x12fc0610 self=0x7b3a839c00
  | sysTid=24450 nice=0 cgrp=default sched=0/0 handle=0x7b2c5384f0
  | state=S schedstat=( 2462204096 250602566 3746 ) utm=209 stm=36 core=1 HZ=100
  | stack=0x7b2c436000-0x7b2c438000 stackSize=1037KB
  | held mutexes=
  at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:-1)
  - waiting to lock <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1) held by thread 1
  at com.commonsware.cwac.saferoom.Helper$OpenHelper.getWritableSupportDatabase(Helper.java:158)
  at com.commonsware.cwac.saferoom.Helper.getWritableDatabase(Helper.java:120)
  at androidx.room.RoomDatabase.setTransactionSuccessful(RoomDatabase.java:286)
  at com.company.deadlocktest.TestDao_Impl.insert(TestDao_Impl.java:49)
  at com.company.deadlocktest.MainActivity$onCreate$d$1.apply(MainActivity.kt:30)
  at com.company.deadlocktest.MainActivity$onCreate$d$1.apply(MainActivity.kt:18)
  at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:59)
  at io.reactivex.internal.operators.observable.ObservableInterval$IntervalObserver.run(ObservableInterval.java:83)
  at io.reactivex.internal.schedulers.ScheduledDirectPeriodicTask.run(ScheduledDirectPeriodicTask.java:38)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
  at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:307)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:302)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
  at java.lang.Thread.run(Thread.java:764)
“主”优先级=5 tid=1等待
|group=“main”scont=1 dsCount=0 flags=1 obj=0x727565f0 self=0x7b42cbea00
|sysTid=24431 nice=-10 cgrp=default sched=0/0 handle=0x7bc78e99a8
|state=S schedstat=(3718987857 647207377 6247)utm=336 stm=34芯=3赫兹=100
|堆栈=0x7fd4c9a000-0x7fd4c9c000堆栈大小=8MB
|保持互斥=
在java.lang.Object.wait(本机方法)
-等待(一个java.lang.Object)
位于java.lang.Thread.parkFor$(Thread.java:2137)
-锁定(一个java.lang.Object)
在sun.misc.Unsafe.park(Unsafe.java:358)
位于java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:868)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:900)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1223)
位于java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:225)
位于java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:286)
位于net.sqlcipher.database.SQLiteDatabase.lock(SQLiteDatabase.java:553)
net.sqlcipher.database.SQLiteDatabase.close(SQLiteDatabase.java:1284)
位于net.sqlcipher.database.SQLiteOpenHelper.close(SQLiteOpenHelper.java:272)
-锁定(com.commonware.cwac.saferoom.Helper$1)
位于com.commonware.cwac.saferoom.Helper$OpenHelper.close(Helper.java:202)
-锁定(com.commonware.cwac.saferoom.Helper$1)
位于com.commonware.cwac.saferoom.Helper.close(Helper.java:146)
在androidx.room.RoomDatabase.close(RoomDatabase.java:189)
在com.company.deadlocktest.MainActivity$onCreate$1.onClick上(MainActivity.kt:38)
在android.view.view.performClick上(view.java:6294)
在android.view.view$PerformClick.run(view.java:24770)
位于android.os.Handler.handleCallback(Handler.java:790)
位于android.os.Handler.dispatchMessage(Handler.java:99)
位于android.os.Looper.loop(Looper.java:164)
位于android.app.ActivityThread.main(ActivityThread.java:6494)
位于java.lang.reflect.Method.invoke(本机方法)
位于com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
“RxComputationThreadPool-1”守护程序prio=5 tid=15被阻止
|group=“main”scont=1 dsCount=0 flags=1 obj=0x12fc0610 self=0x7b3a839c00
|sysTid=24450 nice=0 cgrp=default sched=0/0 handle=0x7b2c5384f0
|state=S schedstat=(246204096 250602566 3746)utm=209 stm=36芯=1赫兹=100
|堆栈=0x7B2C43600-0x7B2C43800堆栈大小=1037KB
|保持互斥=
位于net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:-1)
-等待锁定线程1持有的(com.commonware.cwac.saferoom.Helper$1)
位于com.commonware.cwac.saferoom.Helper$OpenHelper.getWritableSupportDatabase(Helper.java:158)
位于com.commonware.cwac.saferoom.Helper.getWritableDatabase(Helper.java:120)
位于androidx.room.RoomDatabase.setTransactionSuccessful(RoomDatabase.java:286)
位于com.company.deadlocktest.TestDao_Impl.insert(TestDao_Impl.java:49)
在com.company.deadlocktest.MainActivity$onCreate$d$1.apply上(MainActivity.kt:30)
在com.company.deadlocktest.MainActivity$onCreate$d$1.apply上(MainActivity.kt:18)
在io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:59)
at io.reactivex.internal.operators.observable.ObservableInterval$IntervalObserver.run(ObservableInterval.java:83)
在io.reactivex.internal.schedulers.ScheduledDirectPeriodicTask.run(ScheduledDirectPeriodicTask.java:38)
位于java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
位于java.util.concurrent.FutureTask.runAndReset(FutureTask.java:307)
位于java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:302)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
运行(Thread.java:764)
如您所见,Rx线程被锁阻塞,由主线程(
com.commonware.cwac.saferoom.Helper$1)获取,主线程处于等待状态


因此,我试图找出是否有办法避免这个问题,或者这是saferoom/sqlcipher中的某种错误。

我不是RxJava专家,但我认为
clear()
的线程效果不会立即发生


就解决方法而言,不要在主应用程序线程上调用
close()
。通常,我们根本不关闭()
,因为考虑到应用程序中正在发生的一切,我们永远不知道什么时候是好时机。如果您确实想
close()
,请在用于数据库访问的
Schedulers.io()
线程上执行此操作。

谢谢您的回复!我需要关闭数据库,因为我希望由于用户注销而无法访问它。在您的解决方案中,需要从单个线程发出所有数据库请求,对吗?@mol:是的,或者确保在您要关闭数据库时没有任何东西正在访问它。例如,如果在关闭数据库后启动查询,即使这两件事都是在主应用程序线程上完成的,查询也会抛出一个错误,抱怨数据库已关闭
"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x727565f0 self=0x7b42cbea00
  | sysTid=24431 nice=-10 cgrp=default sched=0/0 handle=0x7bc78e99a8
  | state=S schedstat=( 3718987857 647207377 6247 ) utm=336 stm=34 core=3 HZ=100
  | stack=0x7fd4c9a000-0x7fd4c9c000 stackSize=8MB
  | held mutexes=
  at java.lang.Object.wait(Native method)
  - waiting on <0x017bb93d> (a java.lang.Object)
  at java.lang.Thread.parkFor$(Thread.java:2137)
  - locked <0x017bb93d> (a java.lang.Object)
  at sun.misc.Unsafe.park(Unsafe.java:358)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:868)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:900)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1223)
  at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:225)
  at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:286)
  at net.sqlcipher.database.SQLiteDatabase.lock(SQLiteDatabase.java:553)
  at net.sqlcipher.database.SQLiteDatabase.close(SQLiteDatabase.java:1284)
  at net.sqlcipher.database.SQLiteOpenHelper.close(SQLiteOpenHelper.java:272)
  - locked <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1)
  at com.commonsware.cwac.saferoom.Helper$OpenHelper.close(Helper.java:202)
  - locked <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1)
  at com.commonsware.cwac.saferoom.Helper.close(Helper.java:146)
  at androidx.room.RoomDatabase.close(RoomDatabase.java:189)
  at com.company.deadlocktest.MainActivity$onCreate$1.onClick(MainActivity.kt:38)
  at android.view.View.performClick(View.java:6294)
  at android.view.View$PerformClick.run(View.java:24770)
  at android.os.Handler.handleCallback(Handler.java:790)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:164)
  at android.app.ActivityThread.main(ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)


"RxComputationThreadPool-1" daemon prio=5 tid=15 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x12fc0610 self=0x7b3a839c00
  | sysTid=24450 nice=0 cgrp=default sched=0/0 handle=0x7b2c5384f0
  | state=S schedstat=( 2462204096 250602566 3746 ) utm=209 stm=36 core=1 HZ=100
  | stack=0x7b2c436000-0x7b2c438000 stackSize=1037KB
  | held mutexes=
  at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:-1)
  - waiting to lock <0x064ca532> (a com.commonsware.cwac.saferoom.Helper$1) held by thread 1
  at com.commonsware.cwac.saferoom.Helper$OpenHelper.getWritableSupportDatabase(Helper.java:158)
  at com.commonsware.cwac.saferoom.Helper.getWritableDatabase(Helper.java:120)
  at androidx.room.RoomDatabase.setTransactionSuccessful(RoomDatabase.java:286)
  at com.company.deadlocktest.TestDao_Impl.insert(TestDao_Impl.java:49)
  at com.company.deadlocktest.MainActivity$onCreate$d$1.apply(MainActivity.kt:30)
  at com.company.deadlocktest.MainActivity$onCreate$d$1.apply(MainActivity.kt:18)
  at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:59)
  at io.reactivex.internal.operators.observable.ObservableInterval$IntervalObserver.run(ObservableInterval.java:83)
  at io.reactivex.internal.schedulers.ScheduledDirectPeriodicTask.run(ScheduledDirectPeriodicTask.java:38)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
  at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:307)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:302)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
  at java.lang.Thread.run(Thread.java:764)