在开发一个android的项目时,涉及到后台线程调用RestFullservice并同时更新数据库,采用了多线程处理,为了同步两个线程,每个线程的主任务的方法上均使用了synchronized,这是个粗粒度的同步代码:在call service 的时候,并不需要进行同步,因为和另外一个线程并没有资源竞争或者等待,这个时候就进行同步显然过早的hold住了锁,不能让另外一个线程执行任务。 对此问题进行了初步处理:尽可能晚的的hold lock,尽可能早的release lock。
整个系统只使用了一个mutex,按理讲不会出现deadlock的情况,但在后续测试中两个线程却出现了问题,一个处于wait状态,一个处于monitor状态。很明显,死锁了。(2011-2-23update, 此话有误,这两个状态并不表明一定死锁,wait,wait,parkfor都有可能,具体情况要查看线程状态 ) 。在网上查询了synchronized的使用说明,问题依旧。后来通过debug逐渐缩小范围,最终确定了问题:发现在数据库处理的时候使用了transaction,和synchronized存在访问顺序死锁问题
thread1:
db.beginTransaction
synchronized(lockObj)
{
//database operation and other task
}
db.endTransaction
thread2:
synchronized(lockObj)
{
//insert update delete operations
}
分析:
db.begintransaction会导致sqlitedatabase 获取exclusive lock,从而使其他写操作不能进行
1.thread1进入db.beginTransaction。
2.vm切换进程,thread2执行进入sync block内部,发现不能进行写操作,等待。
3.vm切换进程,thread1请求lockObj上的锁,发现已被thread2 hold,等待。
4.死了,隐含的exclusive lock导致锁等待
有关sqlite的锁机制请可看官网
这里还涉及另外一个sqlite数据库问题,就是在单线程多线程下的single connection 和mult connection 的问题
有空再写。
恐有误导,欢迎斧正