Java多线程之死锁
什么是死锁
A、B两台车过桥,桥只能过一台车,A、B分别是桥的两头,A不让B,B不让A
怎么查出死锁(两种方法)
方法一
- JConsole找到本地进程
- 找到线程选项卡,然后检查死锁
- 找到blocked状态的线程,看它需要资源的拥有者
方法二
- JVM自带的命令jps查看进程
- Jstack查看栈的使用情况
怎样从死锁中恢复过来
1. 重启系统,代价大,之前的工作白费,所有正在运行的现场都去掉了
2. 撤销进程,剥夺资源。终止参与死锁的进程,回收他们占的资源,从而解除死锁。这又分两种,一次性撤销参与死锁的全部进程,剥夺全部资源;或者逐步撤销参与死锁的进程。一般来说,逐步撤销要按一定的原则,目的是撤销代价最小的进程,比如按优先级确定线程代价。
3. 进程回退,死锁的线程回退到没有发生死锁的某一点,继续执行。
死锁条件
- 互斥:资源在一段时间内只能被一个线程使用
- 不可抢占:不能强行从别的线程将资源抢走
- 占有且申请:自己占有资源,又申请另一个资源
- 循环
避免死锁的方法
- 打破上面的条件,就能解除或避免死锁
- 避免嵌套锁,只有需要的地方使用锁
- 避免无限期等待也是避免死锁的常用方法
- 使用一些避免死锁的算法:有序资源分配法、银行家算法
N个线程访问N个资源,同时不死锁,用下面算法解决
有序资源排序法
线程所需要的资源统一编号,申请资源时一定要按照编号顺序申请。
例子
- 线程A使用资源的顺序时R1、R2,线程B使用资源的顺序是R2、R1,这样就可能导致死锁
- 有序资源分配法:R1编号为1,R2编号为2
- A申请资源的顺序是R1、R2,B申请资源的顺序是R1、R2,就不会出现死锁了
银行家算法
- 当线程首次申请资源时,要测试改线程对资源的最大需求量,如果资源能满足最大请求量,就分配,否则推迟分配
- 当线程在执行中继续申请资源,先测试该线程本次申请的资源数是否超过了该资源所剩余的总量,如满足则分配,不满足则推迟