概念
死锁是指两个或多个以上的过程在执行过程中,因抢夺资源而造成一种 相互期待的景象,若无外力干预那他们都将无奈推动上来。如果资源短缺,过程的资源申请都可能失去满足,死锁呈现的可能性就很低,否则就会因抢夺无限的资源而陷入死锁。
持有本人的锁,还妄图要他人的锁。
死锁产生的 4 个必要条件(缺一不可)
设想你来到巴黎卢浮宫博物馆,想要排队看看《蒙娜丽莎的微笑》:
- 互斥:一幅画一次只能一个人看。(某个资源只能互斥的应用,例如磁盘、物理内存)
-
申请放弃:
- 申请:张三排队轮到他看蒙娜丽莎的同时,他很贪婪,要看蒙娜丽莎的同时,要看梵高的向日葵(过程在应用已申请资源时,申请应用其余互斥资源)
- 放弃:如果不给张三看向日葵,那么张三就不走(过程放弃对已分配资源的占有)
- 不可剥夺:如果李四正在看向日葵,张三看不了,那么张三就始终堵在蒙娜丽莎后面,不给其他人看(进行曾经申请的资源在没开释前不可被剥夺)
- 循环期待:李四也不满足于看向日葵,也要同时看蒙娜丽莎,而张三占用了蒙娜丽莎,同时也要看向日葵。导致两人谁也不走,陷入了僵局
死锁预防(毁坏死锁的条件)
通过毁坏死锁的四大必要条件,来预防死锁的产生:
- 互斥:有些资源自身就是互斥的,无奈扭转,有的时候是代码设计导致的某些变量互斥了。就像这里的画一样,让多集体一起看不就解决了。
- 申请放弃:一次性调配过程的所有资源。每个人参观必须实现申明好想看的画,而后一次性调配所需的画,不能中途提新的要求。
- 不可剥夺:过程期待新的资源的时候,将本人的资源先开释,等有新的资源后,操作系统才会唤醒它。让这个想看同时两幅画的人先滚到一边去,等两幅画都空了再给他。
- 循环期待:将资源编号,每次只能从小到大申请。将向日葵编号为 1,蒙娜丽莎编号为 2,必须先申请参观 1,持有 1 的同时能力申请 2。
解除正在死锁的状态
剥夺资源:从其余过程剥夺足够数量的资源给死锁过程,已解除死锁状态。
撤销过程:能够间接撤销死锁过程,直至有足够的资源可用为止。
死锁代码
咱们创立了一个资源类,而后让两个线程别离 持有本人的锁 , 同时在尝试获取他人的锁,就会呈现死锁景象。
class HoldLockThread implements Runnable {
private String lockA;
private String lockB;
// 构造函数
public HoldLockThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
//run 办法
@Override
public void run() {synchronized (lockA) {System.out.println(Thread.currentThread().getName()+"本人持有:"+lockA +"尝试取得:"+lockB);
synchronized (lockB) {System.out.println(Thread.currentThread().getName()+"本人持有:"+lockB +"尝试取得:"+lockA);
}
}
}
}
public class DeadLockDemo {public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new HoldLockThread(lockA, lockB), "线程 1").start();
new Thread(new HoldLockThread(lockB, lockA), "线程 2").start();}
}
运行后果,发现 main 线程无奈完结
如何排查死锁
-
通过 jdk 工具 jps、jstack 排查死锁问题
-
应用
jps
命令查看运行的程序。这是 jdk 提供的一个查看以后 java 过程的工具。// 在 IDEA 关上 Terminal,输出 jps -l
咱们能看到 DeadLockDemo 这个类,始终在运行。
-
应用
jstack
查看线程堆栈信息。jstack 3264 //3264 是下面始终运行的过程的编号
通过查看最初一行,咱们看到 Found 1 deadlock,即存在一个死锁。
-
-
通过 jdk 提供的工具 VisualVM 排查死锁问题
VisuaVM:jdk 提供的一个排查 java 问题的工具。可用监控程序的性能、查看 JVM 配置信息、线程堆栈的信息。
-
通过 jdk 提供的工具 jconsole 排查死锁问题
jconsole:jdk 提供的一个可视化的工具,不便排查程序的一些问题,如:程序内存溢出、死锁问题等等。
在本地线程处找到咱们的过程,进行连贯。连贯后在窗口中查看线程堆栈信息,有个“检测死锁”的按钮,可用看到程序的死锁信息。