死锁
-
锁的获取顺序要一致;如果锁的顺序未知,可以使用“加时赛”锁,在获得两个锁之前,先要获得这个“加时赛”锁,从而保证每次只有一个线程以未知的顺序获得这两个锁
-
协作对象之间产生死锁:如果在持有锁时调用某个外部方法,将出现活跃性问题。在这个外部方法中可能会获取其它锁(这可能会产生死锁),或者阻塞时间过长,导致其它线程无法及时获得当前被持有的锁
-
开放调用:调用某个方法时,不需要持有锁
-
资源死锁:当多个线程在相同的资源集合上等待时,也会发生死锁(两个线程需要同样两个资源,一个线程持有一个,等待另一个)
- 线程饥饿死锁:如,一个任务提交另一个任务,并等待被提交任务在单线程的Executor中执行完成;所以有界资源池/线程池与相互依赖的任务不能一起使用
死锁的避免与诊断
-
定时锁:
-
显式使用Lock类中的定时tryLock功能,等待超时后会返回失败信息;
-
只有在同时获取两个锁时才有效,如果在嵌套的方法调用中请求多个锁,即使知道已经持有了外层锁、内层锁请求超时,也无法释放外层锁
-
-
通过线程转储信息分析死锁
-
内置锁与获得他们所在的线程栈帧是相关联的,而显式的Lock只与获得它的线程相关联
其他活跃性危险
-
饥饿:线程优先级使用不当,或持有锁时执行一些无法结束的结构(无限循环)
-
糟糕的响应性:CPU密集型的后台任务会与事件线程共同竞争CPU的时钟周期;不良的锁管理,导致某个线程长时间占有一个锁
-
活锁:线程不断执行相同的操作,而且总会失败;解决方法可以是,在重试机制中引入随机性