「多线程锁」手写死锁案例及排查死锁原因

85 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情

「多线程锁」手写死锁案例及排查死锁原因

一、什么是死锁?

二、手写死锁案例

三、死锁排查

一、什么是死锁?

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那它们都将无法推进下去,如果资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。

image-20230103150901416


二、手写死锁案例

public class DeadLockDemo {
    public static void main(String[] args) {
        final Object objectA = new Object();
        final Object objectB = new Object();
​
        new Thread(() -> {
            synchronized (objectA) {
                System.out.println(Thread.currentThread().getName() + "\t 自己持有A锁,希望获取B锁");
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (objectB) {
                    System.out.println(Thread.currentThread().getName() + "\t 成功获取B锁");
                }
            }
        }, "A").start();
​
        new Thread(() -> {
            synchronized (objectB) {
                System.out.println(Thread.currentThread().getName() + "\t 自己持有B锁,希望获取A锁");
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (objectA) {
                    System.out.println(Thread.currentThread().getName() + "\t 成功获取A锁");
                }
            }
        }, "B").start();
    }
}

案例说明

代码中存在两个线程,其中线程A尝试获取B锁,而线程B尝试获取A锁。

运行结果

image-20230103150914889

解析

线程A在获取B的锁时,A已被上锁,而在线程A睡眠的1s内,线程B也尝试获取A的锁,由图片我们可以知道程序并未停止,二者因争夺资源而造成的一种互相等待的死锁现象。

三、死锁排查

纯指令

在终端输入jps -l找到该类对应的进程号

image-20230103150924880

再输入jstack 28773查看对应堆信息

image-20230103150936568

可以看到双方互相持有、相互等待,以致造成死锁。

图形化

在终端输入jconsole选择对应进程

image-20230103150946469

image-20230103151001161

image-20230103151011424

这里可以清楚看到死锁位置及信息。