1. 什么是死锁
???????? 死锁 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。也就是两个线程拥有锁的情况下,又在尝试获取对方的锁,从而造成程序一直阻塞的情况。
死锁代码演示:
public class DeadLock {
public static void main(String[] args) {
Object lockA = new Object();
Object lockB = new Object();
Thread t1 = new Thread(() -> {
// 1.占有一把锁
synchronized (lockA) {
System.out.println("线程1获得锁A");
// 休眠1s(让线程2有时间先占有锁B)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取线程2的锁B
synchronized (lockB) {
System.out.println("线程1获得锁B");
}
}
});
t1.start();
Thread t2 = new Thread(() -> {
// 占B锁
synchronized (lockB) {
System.out.println("线程2获得锁B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取线程1的锁A
synchronized (lockA) {
System.out.println("线程2获得了锁A");
}
}
});
t2.start();
}
}
?运行结果:
可以使用?jvisualvm / jmc / jconsole 查看死锁:
?
?
2. 死锁产生的原因
形成死锁主要由以下 4 个因素造成的:
- 互斥条件:一个资源只能被?个线程占有,当这个资源被占用之后其他线程就只能等待。
- 不可被剥夺条件:当?个线程不主动释放资源时,此资源一直被拥有线程占有。
- 请求并持有条件:线程已经拥有了?个资源之后,还不满足,又尝试请求新的资源。
- 环路等待条件:多个线程在请求资源的情况下,形成了环路链。
3. 如何解决死锁问题
????????改变产生死锁原因中的任意?个或多个条件就可以解决死锁的问题,其中可以被修改的条件只有两个:请求并持有条件?和?环路等待条件。?
3.1 改变环路等待条件
????????通过修改获取锁的有序性来改变环路等待条件,修改代码如下:?
public class UnDeadLock2 {
public static void main(String[] args) {
Object lockA = new Object();
Object lockB = new Object();
Thread t1 = new Thread(() -> {
synchronized (lockA) {
System.out.println("线程1得到锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println("线程1得到锁B");
System.out.println("线程1释放锁B");
}
System.out.println("线程1释放锁A");
}
}, "线程1");
t1.start();
Thread t2 = new Thread(() -> {
synchronized (lockA) {
System.out.println("线程2得到锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println("线程2得到锁B");
System.out.println("线程2释放锁B");
}
System.out.println("线程2释放锁A");
}
}, "线程2");
t2.start();
}
}
?运行结果:
成功解决死锁。
?
3.2 破坏请求并持有条件
????????可以通过破坏请求并持有条件解决死锁,修改代码如下:
public class UnDeadLock {
public static void main(String[] args) {
Object lockA = new Object();
Object lockB = new Object();
Thread t1 = new Thread(() -> {
synchronized (lockA) {
System.out.println("线程1得到锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (lockB) {
// System.out.println("线程1得到锁B");
// System.out.println("线程1释放锁B");
// }
System.out.println("线程1释放锁A");
}
}, "线程1");
t1.start();
Thread t2 = new Thread(() -> {
synchronized (lockB) {
System.out.println("线程2得到锁B");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (lockA) {
// System.out.println("线程2得到锁A");
// System.out.println("线程2释放锁A");
// }
System.out.println("线程2释放锁B");
}
}, "线程2");
t2.start();
}
}
?运行结果:
可以看到该方法也成功解决了死锁问题。?
|