目录
1. 死锁定义
2. 死锁产生原因
3. 如何解决死锁问题
1. 死锁定义
死锁是指两个或两个以上的进程在执⾏过程中,由于竞争资源或者由于彼此通信⽽造成的⼀种阻塞的现象,若⽆外⼒作⽤,它们都将⽆法推进下去。(也就是两个线程拥有锁的情况下,⼜在尝试获取对⽅锁,从⽽造成程序⼀直阻塞的情况。)
2. 死锁产生原因
形成死锁主要由以下 4 个因素造成的:
① 互斥条件:
⼀个资源只能被⼀个线程占有,当这个资源被占⽤之后其他线程就只能等待。
② 不可被剥夺条件:
当⼀个线程不主动释放资源时,此资源⼀直被拥有线程占有,其他线程不能得到此资源。
③ 请求并持有条件:
线程已经拥有了⼀个资源之后,又尝试请求新的资源。
④ 环路等待条件:
产⽣死锁⼀定是发⽣了线程资源环形链。
形成死锁,四个因素缺一不可。
3. 如何解决死锁问题
打破产生死锁的一个或者多个条件即可。
① 互斥条件:
改变不了。
② 不可被剥夺条件:
改变不了。
③ 请求并持有条件:
可以改变(人为控制)。
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:释放锁A");
}
},"线程2");
t2.start();
}
}
输出
线程1:得到锁A
线程2:得到锁B
(......没有结束)
上面代码产生了死锁。解决方法:
1. 修改获取锁请求并持有条件:
解决死锁方法:破坏请求并持有条件
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();
}
}
输出:
线程1:得到锁A
线程2:得到锁B
线程2:释放锁B
线程1:释放锁A
2. 修改获取锁的有序性来改变环路等待条件:
(使用顺序锁解决死锁问题)
解决死锁方法:修改获取锁的有序性来改变环路等待条件
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();
}
}
输出:
线程1:得到锁A
线程1:得到锁B
线程1:释放锁B
线程1:释放锁A
线程2:得到锁A
线程2:得到锁B
线程2:释放锁B
线程2:释放锁A