死锁的概念以及处理方式
Posted 满眼*星辰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死锁的概念以及处理方式相关的知识,希望对你有一定的参考价值。
死锁定义
在多线程编程中(两个或两个以上的线程)因为资源抢占而早场的线程无线等待的问题
线程和锁的关系(一对多)
- 一个线程可以拥有多把锁
- 一把锁只能被一个线程锁拥有
手写死锁代码
/**
* Created with IntelliJ IDEA.
* Description:死锁
* User: starry
* Date: 2021 -05 -09
* Time: 10:00
*/
public class ThreadDemo36 {
public static void main(String[] args) {
//锁A(资源A)
Object lockA = new Object();
//锁B(资源B)
Object lockB = new Object();
//线程1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程1:得到了锁A");
try {
//休眠1s,让线程2先得到锁B
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:等待获取锁B");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程1:得到了锁B");
}
}
}
},"t1");
t1.start();
//创建并启动线程2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockB) {
System.out.println("线程2:得到了锁B");
try {
//休眠1s,让线程1先得到锁A
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2:等待获取锁A");
//尝试获取锁B
synchronized (lockA) {
System.out.println("线程2:获取到锁A");
}
}
}
},"t2");
t2.start();
}
}
可以看到这时已经发生死锁了,程序一直执行不下去
检查测死锁工具
- jconsole 工具
- jvisualvm 工具
- jmc 工具
具体使用请看我这篇文章:https://blog.csdn.net/starry1441/article/details/116742308
死锁造成的四个条件(同时满足)
- 互斥条件(一个资源只能被一个线程持有,当被一个线程持有之后就不能被其他线程持有)
- 请求拥有条件(一个线程持有了一个资源之后,又试图请求另一个资源)
- 不可剥夺条件(一个资源被一个线程拥有之后,如果这个线程不释放此资源,那么其他线程不能强制获得此资源)
- 环路等待条件(多个线程在获取资源时,形成了一个环形链条)
如何解决死锁
从以下两个条件如手,修改以下条件任意一个:
- 请求拥有条件
- 环路等待条件(最易实现)
我们将线程1 先获取 锁A和锁B,然后再让线程2 获得锁A和锁B,修改环路等待条件,我们来试一试吧
/**
* Created with IntelliJ IDEA.
* Description:解决死锁
* User: starry
* Date: 2021 -05 -09
* Time: 10:00
*/
public class ThreadDemo37 {
public static void main(String[] args) {
//锁A(资源A)
Object lockA = new Object();
//锁B(资源B)
Object lockB = new Object();
//线程1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程1:得到了锁A");
try {
//休眠1s,让线程2先得到锁B
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:等待获取锁B");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程1:得到了锁B");
}
}
}
},"t1");
t1.start();
//创建并启动线程2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("线程2:得到了锁B");
try {
//休眠1s,让线程1先得到锁A
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2:等待获取锁A");
//尝试获取锁B
synchronized (lockB) {
System.out.println("线程2:获取到锁A");
}
}
}
},"t2");
t2.start();
}
}
此时程序正常的结束了,线程1和线程2都分别获取到了锁A锁B
以上是关于死锁的概念以及处理方式的主要内容,如果未能解决你的问题,请参考以下文章