说明
死锁是指两个或两个以上的线程,互相持有对方需要的同步资源,都在等对方放弃该资源,导致互相等待,都无法继续执行。
这是严重问题,因为死锁会让线程处于阻塞状态,无法完成任务
例子1
两只羊都需要用到独木桥,都在等对方放弃独木桥,导致互相等待,都无法过桥
例子2
面试官:我们需要有工作经验的员工
面试人员:那你得让我工作我才有工作经验啊
面试官:你没有工作经验我们怎么招聘你
面试人员:你不让我工作我哪里来的工作经验
例子3
张三和李四大家,互相揪住领子,
张三说:你先放手,我就放手
李四说:你先放手,我就放手
两个人都在等对方放手,导致互相等待,都无法放手
死锁 原因 和 解决
死锁的原因
下面四个条件都成立的时候,就形成死锁:
- 互斥使用:一个资源只能被一个线程占有,当该资源被占有后其他线程就只能等待
- 不可剥夺条件(不可抢占):当一个线程不主动释放资源时,该资源一直被此线程占有
- 请求并持有条件(请求和保持):线程已经拥有了一个资源后,又尝试请求新的资源
- 环路等待条件(循环等待):P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路
死锁的解决
死锁的情况下,如果打破上述任何一个条件,就可以解决死锁,如:不要嵌套使用 synchronized
例子1-可能死锁
package 死锁;
public class std1_可能死锁 {
//锁1
static Object lock1 = new Object();
//锁2
static Object lock2 = new Object();
static class Thread1 extends Thread{
@Override
public void run() {
synchronized (obj1){ // 相当于面试官:我们要有工作经验的
System.out.println(this.getClass().getSimpleName()+" 申请到锁 obj1");
synchronized (obj2){ // 相当于:录取面试人员
System.out.println(this.getClass().getSimpleName()+" 申请到锁 obj2");
}
}
}
}
static class Thread2 extends Thread{
@Override
public void run() {
synchronized (obj2){ // 相当于:录取面试人员
System.out.println(this.getClass().getSimpleName()+" 申请到锁 obj2");
synchronized (obj1){ // 相当于:就有工作经验
System.out.println(this.getClass().getSimpleName()+" 申请到锁 obj1");
}
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
thread1.start();
Thread2 thread2 = new Thread2();
thread2.start();
}
}
例子2-一定死锁
package 死锁;
public class std2_死锁 {
//锁1
static Object lock1 = new Object();
//锁2
static Object lock2 = new Object();
static class Thread1 extends Thread{
@Override
public void run() {
synchronized (obj1){ // 相当于面试官:我们要有工作经验的
System.out.println("Thread1 申请到锁 obj1");
try {
// 休眠不会释放锁,让 Thread2 执行,增加死锁概率
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (obj2){ // 相当于:录取面试人员
System.out.println("Thread1 申请到锁 obj2");
}
}
}
}
static class Thread2 extends Thread{
@Override
public void run() {
synchronized (obj2){ // 相当于:录取面试人员
System.out.println("Thread2 申请到锁 obj2");
try {
// 休眠不会释放锁,让 Thread1 执行,增加死锁概率
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (obj1){ // 相当于:就有工作经验
System.out.println("Thread2 申请到锁 obj1");
}
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
thread2.start();
}
}
参考:
https://blog.csdn.net/m0_49622667/article/details/124270170
