Java中ReentrantReadWriteLock与synchronized混用死锁问题咨询
死锁原因与疑问解答
核心死锁逻辑
你的初步猜测存在偏差,结合线程dump给出的阻塞现象,死锁是典型的循环持有等待问题,触发时序如下:
- Worker线程执行
run方法时,调用static synchronized修饰的Utils.scheduleTask,首先拿到Utils.class类锁,向线程池提交延迟为0的任务。 - 由于操作系统调度的不确定性,提交的任务在
scheduleTask方法还未执行完成、Worker线程还持有Utils.class锁时,就被schedule线程抢先启动执行。 schedule线程执行任务的过程中,拿到了Worker实例的内置锁(结合你去掉doSomething的synchronized就能解决死锁的现象,你的示例代码中getData方法漏加了synchronized修饰,实际业务代码中该方法应该是同步方法),之后尝试获取ReentrantReadWriteLock的读锁时陷入阻塞。- Worker线程待
scheduleTask执行完成、释放Utils.class锁后,执行synchronized修饰的doSomething方法,拿到Worker实例的内置锁,之后调用Utils.getIntValue时,由于实际业务中getIntValue也是static synchronized修饰的,需要获取Utils.class类锁,此时该锁被schedule线程持有,Worker线程陷入阻塞。
两个线程各自持有对方需要的锁,同时等待对方释放锁,形成死锁。去掉doSomething的synchronized修饰后,循环等待的链路被打破,死锁自然消失。
你的疑问解答
1. ReentrantReadWriteLock实例如何感知到引用它的Worker实例已经被其他线程持有内置锁?
完全不会感知。ReentrantReadWriteLock是基于AQS实现的显式锁,和Java对象的内置监视器锁是两套完全独立的锁实现,彼此没有任何关联逻辑,不存在互相感知的机制。
2. 是否在scheduleTask方法执行完成返回后,Utils类的类锁还处于被持有状态,导致提交的定时Runnable运行时还需要等待该锁?
不会。static synchronized方法的锁持有周期和方法执行周期完全一致,方法执行结束返回时,Utils.class的类锁就会被自动释放。后续定时任务运行时不需要等待该锁,除非任务内部也调用了Utils类的静态同步方法。
内容的提问来源于stack exchange,提问作者CrazyGreenHand
相关产品推荐
相关产品推荐

