面试官:什么是死锁?死锁产生的原因?如何避免死锁?

简介: 死锁是一种非常严重的bug,是说多个线程同时被阻塞,线程中的一个或者多个又或者全部都在等待某个资源被释放,造成线程无限期的阻塞,导致程序不能正常终止。

🥧什么是死锁?

死锁是一种非常严重的bug,是说多个线程同时被阻塞,线程中的一个或者多个又或者全部都在等待某个资源被释放,造成线程无限期的阻塞,导致程序不能正常终止。


🍽️为了进一步说明死锁,有哲学家就餐这样的一个问题:


有一个桌子,哲学家们围成一圈,每两个哲学家中间有一支筷子

image.png

哲学家只能两件事:思考或者吃饭,思考时候就不会动筷子,吃饭时会拿起左右手旁边的筷子(先拿左后拿右)

image.png



如果有一个哲学家想吃饭,但是筷子被占用,就得等别人吃完进入思考后,才能获得筷子,等待的过程称为阻塞等待

image.png


在等待的情形中,会出现下面这样一种情况:所有人都处于等待筷子中,即所有哲学家都获取到左边的筷子,一直获取不到右边的筷子,这种情况称为死锁

image.png



🍙死锁产生原因?

🔏结合上述哲学家的例子,说明死锁产生的四个必要条件:


🍂互斥使用:当资源被一个线程使用或者占用时,别的线程不能使用该资源

🍂不可抢占:获取资源的一方,不能从正在使用资源的一方抢占掠夺资源,资源只能被使用者主动释放

🍂请求和保持:资源请求者在请求别的资源时,同时保持对已有资源的占有

🍂循环等待:即p1占有p2的资源,p2占有p3的资源,p3占有p1的资源,这样形成了一个等待环路


上述这四个条件满足即造成的结果就是死锁


👁️看这样的一段可能产生死锁的代码:

public class DeadLock {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                try {
                    synchronized (lock1){
                        Thread.sleep(1000);
                        synchronized (lock2){
                            System.out.println("输出t1");
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                try {
                    synchronized (lock2){
                        Thread.sleep(1000);
                        synchronized (lock1){
                            System.out.println("输出t2");
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        t2.start();
    }
}


👁‍🗨️说明:


t1先申请lock1,lock2,释放lock2,lock1

t2后申请lock2,lock1,释放lock1,lock2

这种情况不会产生死锁


t2先申请lock2,lock1,释放lock1,lock2

t1后申请lock1,lock2,释放lock2,lock1

这种情况也不会产生死锁


t1申请到lock1,t2申请到lock2,这样t1就申请不到lock2,t2就申请不到lock1,都等着对方释放资源,这样就产生了死锁


因为让t1,t2申请第一个锁的时候都等待了1秒,所以产生死锁的概率接近100%


运行结果:没有执行输出,产生死锁

微信图片_20221029150345.jpg



🍚如何使用IDEA查看程序是否产生死锁?

🕐第一步:点击下方红圈内的Terminal

微信图片_20221029150347.jpg



🕑第二步:在下方命令窗口输入jconsole,然后回车

微信图片_20221029150419.jpg



🕒第三步:双击发生死锁对应的类

微信图片_20221029150421.jpg



🕓第四步:切换到线程,点击下面的检查死锁

微信图片_20221029150446.jpg



🕔第五步:即可看到发生死锁的线程

微信图片_20221029150614.jpg


🍣如何避免死锁?

死锁的产生必须满足互斥使用,不可抢占,请求和保持,循环等待这四个条件,但是只要破坏其中任意一个条件即可破坏死锁,其中最容易破坏的就是循环等待这个条件,那么如何破坏循环等待这个条件呢?


多个线程约定好一定的顺序,按照这个顺序加锁释放锁


👁️对上述产生死锁的代码改造:将加锁顺序都改为lock1,lock2,看看打印结果

public class DeadLock {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                try {
                    synchronized (lock1){
                        Thread.sleep(1000);
                        synchronized (lock2){
                            System.out.println("输出t1");
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                try {
                    synchronized (lock1){
                        Thread.sleep(1000);
                        synchronized (lock2){
                            System.out.println("输出t2");
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        t2.start();
    }
}


打印结果:可以看到结果可以正常输出而不产生死锁

微信图片_20221029150648.jpg




相关文章
|
12天前
|
SQL 算法 关系型数据库
面试:什么是死锁,如何避免或解决死锁;MySQL中的死锁现象,MySQL死锁如何解决
面试:什么是死锁,死锁产生的四个必要条件,如何避免或解决死锁;数据库锁,锁分类,控制事务;MySQL中的死锁现象,MySQL死锁如何解决
|
4月前
|
Java API
Java面试题:解释死锁的概念,给出避免死锁的常见策略。你能给我一个具体的例子吗?
Java面试题:解释死锁的概念,给出避免死锁的常见策略。你能给我一个具体的例子吗?
42 0
|
6月前
面试官:什么是死锁?死锁产生的原因?如何避免死锁?
面试官:什么是死锁?死锁产生的原因?如何避免死锁?
45 0
面试官:什么是死锁?死锁产生的原因?如何避免死锁?
|
6月前
|
Java
Java线程面试题:什么是死锁?如何避免?
Java线程面试题:什么是死锁?如何避免?
72 0
|
6月前
|
算法 安全 调度
[操作系统] 面试宝典之~死锁连环系列
[操作系统] 面试宝典之~死锁连环系列
|
Java
第二季:10.死锁编码及定位分析【Java面试题】
第二季:10.死锁编码及定位分析【Java面试题】
66 0
|
安全 Java
【Java面试】什么是死锁?
【Java面试】什么是死锁?
59 0
|
安全 算法 Java
【Java面试宝典】线程安全问题|线程死锁的出现|线程安全的集合类
【Java面试宝典】线程安全问题|线程死锁的出现|线程安全的集合类
127 0
|
存储 关系型数据库 MySQL
面试官:解释下什么是死锁?为什么会发生死锁?怎么避免死锁?
开局先来个段子: 面试官: 解释下什么是死锁? 应聘者: 你录用我,我就告诉你 面试官: 你告诉我,我就录用你 应聘者: 你录用我,我就告诉你 面试官: 滚!
|
算法 Java 调度
Java 最常见的面试题:怎么防止死锁?
Java 最常见的面试题:怎么防止死锁?
113 0