概念
死锁是指两个或多个以上的进程在执行过程中,因争夺资源而造成一种互相等待的现象,若无外力干涉那他们都将无法推进下去。如果资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。
持有自己的锁,还妄图要别人的锁。
死锁产生的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提供的一个可视化的工具,方便排查程序的一些问题,如:程序内存溢出、死锁问题等等。
在本地线程处找到我们的进程,进行连接。连接后在窗口中查看线程堆栈信息,有个 “检测死锁” 的按钮,可用看到程序的死锁信息。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。