死锁产生条件
死锁的产生必须具备以下四个条件:
条件 | |
---|---|
互斥 | 指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。 |
占有且等待 | 指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源。 |
不可抢占 | 指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源。 |
循环等待 | 指在发生死锁时,必然存在一个线程—资源的环形链,即线程集合{T0, T1, T2, …, Tn}中的T0正在等待一个T1占用的资源,T1正在等待T2占用的资源,……Tn正在等待已被T0占用的资源 |
package com.example.thread;
/**
* @Description:
* @Author: baxiang
* @Date: 2021/9/28.
*/
public class DeadLockTest {
//1. 创建共享资源
private static Object resourceA = new Object();
private static Object resourceB = new Object();
public static void main(String[] args) {
//2. 创建线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
//2.1获取资源A的锁
synchronized (resourceA) {
System.out.println(Thread.currentThread() + " get ResourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.1获取资源B的锁
System.out.println(Thread.currentThread() + "waiting get ResourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get ResourceB");
}
}
}
});
//3. 创建线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
//3.1获取资源B的锁
synchronized (resourceB) {
System.out.println(Thread.currentThread() + " get ResourceB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.2获取资源A的锁
System.out.println(Thread.currentThread() + "waiting get ResourceA");
synchronized (resourceA) {
System.out.println(Thread.currentThread() + "get ResourceA");
}
}
;
}
});
//3. 启动线程
threadA.start();
threadB.start();
}
}
避免线程死锁
互斥这个条件我们没有办法破坏,因为我们用锁为的就是互斥,其他三个条件都有办法可以破坏
对于“占用且等待”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。
对于“不可抢占”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动
释放它占有的资源,这样不可抢占这个条件就破坏掉了。
对于“循环等待”这个条件,可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序
的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环
了。
目前只有请求并持有和环路等待条件是可以被破坏的。
public class DeadLockBrokenTest {
//1. 创建共享资源
private static Object resourceA = new Object();
private static Object resourceB = new Object();
public static void main(String[] args) {
//2. 创建线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
//2.1获取资源A的锁
synchronized (resourceA) {
System.out.println(Thread.currentThread() + " get ResourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.1获取资源B的锁
System.out.println(Thread.currentThread() + "waiting get ResourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get ResourceB");
}
}
}
});
//3. 创建线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
//3.1获取资源A的锁
synchronized (resourceA) {
System.out.println(Thread.currentThread() + " get ResourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.2获取资源B的锁
System.out.println(Thread.currentThread() + "waiting get ResourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get ResourceB");
}
}
}
});
//3. 启动线程
threadA.start();
threadB.start();
}
}