文章

Java多线程死锁代码样例

题目

使用代码展示出两个线程死锁的情况

代码

public class Main {
    private static final ReentrantLock LOCK_A = new ReentrantLock();
    private static final ReentrantLock LOCK_B = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        //构建双线程死锁
        Thread threadA = new Thread(() -> {
            LOCK_A.lock();
            try {
                System.out.println("线程A获取到了锁A");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LOCK_B.lock();
                try {
                    System.out.println("线程A获取到了锁B");
                } finally {
                    LOCK_B.unlock();
                }
            } finally {
                LOCK_A.unlock();
            }
        });
        Thread threadB = new Thread(() -> {
            LOCK_B.lock();
            try {
                System.out.println("线程B获取到了锁B");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LOCK_A.lock();
                try {
                    System.out.println("线程B获取到了锁A");
                } finally {
                    LOCK_A.unlock();
                }
            } finally {
                LOCK_B.unlock();
            }
        });
        threadA.start();
        threadB.start();
        //构建死锁检测
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean a = LOCK_A.isLocked();
            boolean b = LOCK_B.isLocked();
            if (a && b) {
                System.out.println("检测到死锁");
            }
        }
    }
}

运行后,我们可以在控制台看到以下的输出:

线程A获取到了锁A
线程B获取到了锁B
检测到死锁
检测到死锁
检测到死锁

这样就成功完成死锁的场景呈现。

总结

在前面的代码中,我们实际上构建了满足以下要求的死锁场景:

  • 互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。

  • 不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。

  • 请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。

  • 循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源

那么想要解决死锁,那就破环掉上述要求之一即可。

License:  CC BY 4.0