android sqlite数据库死锁,关闭sqlite数据库时出现死锁

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

这是来自测试项目的一些代码,我试着重现这个问题(重现大约30%的时间):

class MainActivity : AppCompatActivity() {

lateinit var db: TestDb

private val disposables = CompositeDisposable()

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

openStorage("password")

val d = Observable.interval(100, TimeUnit.MICROSECONDS)

.map { db.testDao().insert(TestEntity()) }

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe({ status.text = "WRITING" }, {})

disposables.add(d)

closeDbButton.setOnClickListener {

disposables.clear()

db.close()

status.text = "DB CLOSED"

}

}

@Synchronized

fun openStorage(storageSecret: String) {

val factory = SafeHelperFactory(storageSecret.toCharArray())

db = Room.databaseBuilder(this, TestDb::class.java, TestDb.DATABASE_NAME)

.openHelperFactory(factory)

.build()

}

}

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

我还试图分析线程转储:

"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)

如您所见,Rx线程被锁阻塞,由主线程获取(

<0x064ca532> com.commonsware.cwac.saferoom.Helper$1

),主线程处于等待状态。

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

本次更新对于支持库来说,接口改动不大,模块版的话是尽量和支持库接口保持一致,所以对于以前的模块接口可能改动就大了。 要解决多线程问题,主要是对sqlite3的锁机制进行了解,和事务有密切的关系。本次更新的版本在开始事务,增加了一个 事务锁状态 的参数。 拿简单的话来描述就是 开始事务 如果 设置了 事务锁状态_ 立即 参数,那么这个候其他线程的连接就不能写操作了,但是可以读操作,但是在提交事务也要等待所有读操作完成了才能提交。 设置了 事务锁状态_ 独占 参数,那么这个候其他线程的连接读写都不可以了。 在等待的候就处于繁忙状态,我们可以设置 数据库.繁忙超 ()来设置等待间。 还有种情况还是会 死锁 ,就是记录集没有关闭,而且这次更新的支持库和模块都是必须 手动关闭记录集 的,所以一定注意。 当然多进程和多线程是一个道理,具体操作看例子。 esqlite3 V1.1 相对于1.0的更新 1、增加了全局命令: S3互斥体进入 S3互斥体退出 S3聚合上下文 S3取数据库自上下文 2、增加了zySqlite数据库 命令 繁忙超 繁忙处理 取文件名 是否只读 取互斥体 是否自动提交 进度处理 取下一记录集 取总影响行 3、增加了 zySqlite记录集 命令 是否繁忙 是否只读 取数据库句柄 取行数 4、数据库.开始事务() 增加了 事务锁状态 参数,此参数在多线程中非常重要。 5、记录集必须手动关闭,任何内部方法都不再自动关闭
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值