Java 死锁 以及实例

2018-07-05  本文已影响0人  博弈史密斯

先看一个死锁的代码:

public class ClassB {
    
    private static ClassB instance;
    
    public static ClassB getInstance() {
        if (instance == null) {
            instance = new ClassB();
        }
        return instance;
    }

    public synchronized void b1() {
        ...
    }
    
    public synchronized void b2() {
        Thread.sleep(2000);
        
        ClassA.getInstance.a2();
    }
}

public class ClassA {
    
    private static ClassA instance;
    
    public static ClassA getInstance() {
        if (instance == null) {
            instance = new ClassA();
        }
        return instance;
    }

    public synchronized void a1() {
        ClassB.getInstance.b1();
    }
    
    public synchronized void a2() {
        ...
    }
}

Thread thread1 = new Thread() {

    @Override
    public void run() {
        ClassA.getInstance.a1();
    }
};

Thread thread2 = new Thread() {

    @Override
    public void run() {
        ClassB.getInstance.b2();
    }
};

//Main 方法中:
thread2.start();
thread1.start();

先启动 thread2,thread2 中调用ClassB 的 b2,b2 中先睡了两秒,然后调用a2;
再启动 thread1,thread1 中调用ClassA 的 a1,a1 中调用 b1;

a1 调用 b1 时,因为 b2 在 sleep,没有释放锁,所以a1 等待 b2 释放锁
b2 sleep 时间过后,调用 a2,而 a1 这时还在执行,没有释放锁,所以 b2 也在等待 a1 释放锁

所以就出现了 ClassA 等待 ClassB 释放锁,而 ClassB 也在等待 ClassA 释放锁 的无限等待的情况。
这种情况便称为 死锁。

用一副图来标识上面的调用关系:


上面的代码是 两个类 互相调用:A->B->A->B...,产生死锁。
而实际中的死锁有可能更隐蔽,有可能是 A->B->C->A->B... 的情况,形成闭环,有可能闭环中的类更多。

死锁的根本原因是出现了嵌套锁,要避免嵌套锁的发生,下面给出一种解决方式:

public void b2() {

    synchronized(this) {
        Thread.sleep(2000);
    }
    
    ClassA.getInstance.a2();
}

synchronized 不再修饰方法,而是修饰一个代码块,调用 a2 不放在代码块中。
这样便断开了锁链,不能形成死锁了。

下面给出一个 trace 文件中的死锁的日志:


重点看 第8行 和 第23行,thread1 等待 thread14 ,thread14 在等待 thread1,形成死锁。

上一篇 下一篇

猜你喜欢

热点阅读