java 多线程死锁

说明

死锁是指两个或两个以上的线程,互相持有对方需要的同步资源,都在等对方放弃该资源,导致互相等待,都无法继续执行。

这是严重问题,因为死锁会让线程处于阻塞状态,无法完成任务

例子1

两只羊都需要用到独木桥,都在等对方放弃独木桥,导致互相等待,都无法过桥

例子2

面试官:我们需要有工作经验的员工

面试人员:那你得让我工作我才有工作经验啊

面试官:你没有工作经验我们怎么招聘你

面试人员:你不让我工作我哪里来的工作经验

例子3

张三和李四大家,互相揪住领子,

张三说:你先放手,我就放手
李四说:你先放手,我就放手

两个人都在等对方放手,导致互相等待,都无法放手

死锁 原因 和 解决

死锁的原因

下面四个条件都成立的时候,就形成死锁:

  1. 互斥使用:一个资源只能被一个线程占有,当该资源被占有后其他线程就只能等待
  2. 不可剥夺条件(不可抢占):当一个线程不主动释放资源时,该资源一直被此线程占有
  3. 请求并持有条件(请求和保持):线程已经拥有了一个资源后,又尝试请求新的资源
  4. 环路等待条件(循环等待):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


原文出处:/show_1IX4rVe0apG4.html