【工作随手记】deaklock排查
Published on 2023-01-30 11:29 in 暂未分类 with 是奉壹呀

【工作随手记】deaklock排查

    生产环境当中还没真正遇到过死锁的问题。有些疑似死锁的问题,后来经过排查也只是其它问题导致的。所以通过jstack到底怎样排查死锁问题有点疏忽了。这里作个记录。

    模拟一个死锁

    顺便复习一下。

    死锁的产生有四个必要的条件

    互斥使用,即当资源被一个线程占用时,别的线程不能使用
    不可抢占,资源请求者不能强制从资源占有者手中抢夺资源,资源只能由占有者主动释放
    请求和保持,当资源请求者在请求其他资源的同时保持对原因资源的占有
    循环等待,多个线程存在环路的锁依赖关系而永远等待下去,例如T1占有T2的资源,T2占有T3的资源,T3占有T1的资源,这种情况可能会形成一个等待环路
    对于死锁产生的四个条件只要能破坏其中一条即可让死锁消失,但是条件一是基础,不能被破坏。

    模拟一个死锁。

     private static String lock1 = "lock1";
        private static String lock2 = "lock2";
    
        public static void main(String[] args) {
            Runnable r1 = new Runnable() {
                @Override
                public void run() {
                    synchronized (lock1){
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread() + " 锁住了lock1");
                        synchronized (lock2){
                            System.out.println(Thread.currentThread() + " 锁住了lock2");
                        }
                    }
                }
            };
    
            Runnable r2 = new Runnable() {
                @Override
                public void run() {
                    synchronized (lock2){
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread() + " 锁住了lock2");
                        synchronized (lock1){
                            System.out.println(Thread.currentThread() + " 锁住了lock1");
                        }
                    }
                }
            };
    
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            executorService.submit(r1);
            executorService.submit(r2);
    
        }
    

    执行输出

    Thread[pool-1-thread-1,5,main] 锁住了lock1
    Thread[pool-1-thread-2,5,main] 锁住了lock2
    

    后面一直卡住,通过idea查看堆栈信息可以看到,两个线程互相一直在等待对方释放锁。

    "pool-1-thread-2" #13 prio=5 os_prio=0 tid=0x000000001ebc6000 nid=0xcf950 waiting for monitor entry [0x00000000207fe000]
    java.lang.Thread.State: BLOCKED (on object monitor)
    at com.nyp.test.DeadlockTest$2.run(DeadlockTest.java:49)

    • waiting to lock <0x000000076b19de70> (a java.lang.String)
    • locked <0x000000076b19dea8> (a java.lang.String)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at java.lang.Thread.run(Thread.java:748)

    "pool-1-thread-1" #12 prio=5 os_prio=0 tid=0x000000001ebc5000 nid=0xcfa20 waiting for monitor entry [0x00000000206ff000]
    java.lang.Thread.State: BLOCKED (on object monitor)
    at com.nyp.test.DeadlockTest$1.run(DeadlockTest.java:31)

    • waiting to lock <0x000000076b19dea8> (a java.lang.String)
    • locked <0x000000076b19de70> (a java.lang.String)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at java.lang.Thread.run(Thread.java:748)

    通过idea我们很方便的观察到了两个线程在等待对方释放锁,而且通过观察其它的堆栈信息我们也能方便的知道,两个线程也分别锁住了对方想要申请的锁,因此造成了死锁。

    但是在生产环境中,通过jstack会打印出一大堆线程的信息,而且只有有并发环境必然会上锁,堆栈信息当中必然会出现waiting for monitor``waiting on condition``locked等信息,这并不是死锁的完全充要条件。

    将代码放到生产环境。通过jstack pid命令,可以看到会出现明确的deadlock的信息。

    Found one Java-level deadlock:

    "pool-4-thread-2":
    waiting to lock monitor 0x00007f0c24026408 (object 0x00000005d0e7a708, a java.lang.String),
    which is held by "pool-4-thread-1"
    "pool-4-thread-1":
    waiting to lock monitor 0x00007f0c24025c78 (object 0x00000005d0e7a740, a java.lang.String),
    which is held by "pool-4-thread-2"

    Java stack information for the threads listed above:

    "pool-4-thread-2":
    at com.alpha.data.util.DeadlockTest$2.run(DeadlockTest.java:49)

    • waiting to lock <0x00000005d0e7a708> (a java.lang.String)
    • locked <0x00000005d0e7a740> (a java.lang.String)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at java.lang.Thread.run(Thread.java:750)
      "pool-4-thread-1":
      at com.alpha.data.util.DeadlockTest$1.run(DeadlockTest.java:31)
    • waiting to lock <0x00000005d0e7a740> (a java.lang.String)
    • locked <0x00000005d0e7a708> (a java.lang.String)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at java.lang.Thread.run(Thread.java:750)

    Found 1 deadlock.

    也就是在生产环境中,通过jstack排查死锁问题时 ,只需要盯着deadlock字样即可,如果有死锁会明显的提示出产生死锁的代码所在。否则,便是没有死锁。

    顺便复习一下通过jstack排查cpu占用高的问题

    1.通过top命令找到cpu占用高的应用程序进程
    2.通过top -H -p pid查看该应用中占用CPU高的线程。
    3.通过printf "%x\n" pid 将线程高的线程号转为十六进制。
    4.通过jstack过滤该十六进制的关键信息。jstack pid | grep 十六进制 -c 10

    这样就可以看到占用CPU高的代码位置。

    总结:就是先查到占用高的应用和具体的线程,然后根据线程到堆积信息查找即可。
    不过堆栈信息非十进制,需提前把线程号转为十六进制。

    posted @   是奉壹呀  阅读(305)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 周边上新:园子的第一款马克杯温暖上架
    · Open-Sora 2.0 重磅开源!
    · .NET周刊【3月第1期 2025-03-02】
    · 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
    · [AI/GPT/综述] AI Agent的设计模式综述
    点击右上角即可分享
    微信分享提示