死锁分析以及检测工具详解

2020-02-20 18:07:44 浏览数 (2)

锁的状态

死锁:线程1等待线程2的互斥持有资源,而线程2等着线程1的互斥持有资源,两个线程都无法进行执行。

活锁:线程持续重试一个总是失败的操作,导致无法继续执行。(不是本文的重点)

饿死:线程一直被调度器延迟访问其赖以执行的资源,也许是调度器先于低优先级的线程而执行高优先级的线程,同时总是会有一个高优先级的线程可以执行,饿死也叫做无限延迟。

死锁的案例

代码如下所示:

代码语言:javascript复制
package com.karl.concurrent.deadlock;

/**
 * 描述:  死锁的场景
 *
 * @author mh
 * @create 2020-02-11 15:43
 */
public class DeadLockTest {
    private Object object1 = new Object();
    private Object object2 = new Object();

    public static void main(String[] args) {
        DeadLockTest deadLockTest = new DeadLockTest();

        Runnable runnable1 = () -> {
            while (true) {
                deadLockTest.method01();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {

                }
            }
        };

        Thread thread01 = new Thread(runnable1, "thread01");

        Runnable runnable2 = () -> {
            while (true) {
                deadLockTest.method02();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {

                }
            }
        };
        Thread thread02 = new Thread(runnable2, "thread02");


        thread01.start();
        thread02.start();
    }


    public void method01() {
        synchronized (object1) {
            synchronized (object2) {
                System.out.println("method01 invoked");
            }

        }
    }


    public void method02() {
        synchronized (object2) {
            synchronized (object1) {
                System.out.println("method02 invoked");
            }
        }
    }

}

控制台:

根据图中我们可以看出,程序在运行中,但一直没有任何输出。

图解:

死锁的检测工具

java VisualVM

打开方式:jvisualvm命令即可

界面:

双击本地下的我们刚才执行的程序DeadLockTest,的到如下页面:

我们选择Dump线程

如图可知:

  • 线程01 02 在阻塞状态
  • 都在等待获取monitor持有权
  • 线程01 等待锁0x000000076ada8128,而且已经锁定了0x000000076ada8138。
  • 线程02 等待0x000000076ada8138,而且已经锁定了0x000000076ada8128。刚好和线程01 是相反的。

具体的细节大家可以在本地演示一下。

通过命令行工具检测死锁

jps -l 找到我们的程序id

代码语言:javascript复制
95007 com.karl.concurrent.deadlock.DeadLockTest

jstack 95007 查看线程情况

代码语言:javascript复制
2020-02-11 18:15:10
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):

"Attach Listener" #14 daemon prio=9 os_prio=31 tid=0x00007ffe9308c000 nid=0xa603 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #13 prio=5 os_prio=31 tid=0x00007ffe940a6800 nid=0xe03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"thread02" #12 prio=5 os_prio=31 tid=0x00007ffe940a5800 nid=0xa703 waiting for monitor entry [0x0000700002706000]
   java.lang.Thread.State: BLOCKED (on object monitor)
  at com.karl.concurrent.deadlock.DeadLockTest.method02(DeadLockTest.java:60)
  - waiting to lock <0x000000076aeefc20> (a java.lang.Object)
  - locked <0x000000076aeefc30> (a java.lang.Object)
  at com.karl.concurrent.deadlock.DeadLockTest.lambda$main$1(DeadLockTest.java:31)
  at com.karl.concurrent.deadlock.DeadLockTest$$Lambda$2/381259350.run(Unknown Source)
  at java.lang.Thread.run(Thread.java:748)

"thread01" #11 prio=5 os_prio=31 tid=0x00007ffe940a5000 nid=0xa903 waiting for monitor entry [0x0000700002603000]
   java.lang.Thread.State: BLOCKED (on object monitor)
  at com.karl.concurrent.deadlock.DeadLockTest.method01(DeadLockTest.java:50)
  - waiting to lock <0x000000076aeefc30> (a java.lang.Object)
  - locked <0x000000076aeefc20> (a java.lang.Object)
  at com.karl.concurrent.deadlock.DeadLockTest.lambda$main$0(DeadLockTest.java:18)
  at com.karl.concurrent.deadlock.DeadLockTest$$Lambda$1/1607521710.run(Unknown Source)
  at java.lang.Thread.run(Thread.java:748)

"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007ffe94049000 nid=0x3e03 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007ffe95875000 nid=0x4003 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007ffe93053800 nid=0x3c03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007ffe93053000 nid=0x3b03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007ffe93052000 nid=0x3a03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007ffe93050800 nid=0x3803 runnable [0x0000700001eee000]
   java.lang.Thread.State: RUNNABLE
  at java.net.SocketInputStream.socketRead0(Native Method)
  at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
  at java.net.SocketInputStream.read(SocketInputStream.java:171)
  at java.net.SocketInputStream.read(SocketInputStream.java:141)
  at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
  at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
  at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
  - locked <0x000000076ac83770> (a java.io.InputStreamReader)
  at java.io.InputStreamReader.read(InputStreamReader.java:184)
  at java.io.BufferedReader.fill(BufferedReader.java:161)
  at java.io.BufferedReader.readLine(BufferedReader.java:324)
  - locked <0x000000076ac83770> (a java.io.InputStreamReader)
  at java.io.BufferedReader.readLine(BufferedReader.java:389)
  at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007ffe9301d800 nid=0x3703 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007ffe9282a000 nid=0x4c03 in Object.wait() [0x0000700001be2000]
   java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x000000076ab08ed0> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
  - locked <0x000000076ab08ed0> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
  at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007ffe9300f800 nid=0x4d03 in Object.wait() [0x0000700001adf000]
   java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x000000076ab06bf8> (a java.lang.ref.Reference$Lock)
  at java.lang.Object.wait(Object.java:502)
  at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
  - locked <0x000000076ab06bf8> (a java.lang.ref.Reference$Lock)
  at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=31 tid=0x00007ffe9581c000 nid=0x4e03 runnable

"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ffe92806000 nid=0x1d07 runnable

"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ffe92807000 nid=0x1f03 runnable

"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ffe92807800 nid=0x2203 runnable

"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ffe9280b000 nid=0x2a03 runnable

"GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007ffe9280b800 nid=0x2b03 runnable

"GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007ffe9280c800 nid=0x5303 runnable

"GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007ffe9280d000 nid=0x5103 runnable

"GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007ffe9280d800 nid=0x2d03 runnable

"VM Periodic Task Thread" os_prio=31 tid=0x00007ffe9400a000 nid=0x5503 waiting on condition

JNI global references: 319


Found one Java-level deadlock:
=============================
"thread02":
  waiting to lock monitor 0x00007ffe92826cb8 (object 0x000000076aeefc20, a java.lang.Object),
  which is held by "thread01"
"thread01":
  waiting to lock monitor 0x00007ffe928282b8 (object 0x000000076aeefc30, a java.lang.Object),
  which is held by "thread02"

Java stack information for the threads listed above:
===================================================
"thread02":
  at com.karl.concurrent.deadlock.DeadLockTest.method02(DeadLockTest.java:60)
  - waiting to lock <0x000000076aeefc20> (a java.lang.Object)
  - locked <0x000000076aeefc30> (a java.lang.Object)
  at com.karl.concurrent.deadlock.DeadLockTest.lambda$main$1(DeadLockTest.java:31)
  at com.karl.concurrent.deadlock.DeadLockTest$$Lambda$2/381259350.run(Unknown Source)
  at java.lang.Thread.run(Thread.java:748)
"thread01":
  at com.karl.concurrent.deadlock.DeadLockTest.method01(DeadLockTest.java:50)
  - waiting to lock <0x000000076aeefc30> (a java.lang.Object)
  - locked <0x000000076aeefc20> (a java.lang.Object)
  at com.karl.concurrent.deadlock.DeadLockTest.lambda$main$0(DeadLockTest.java:18)
  at com.karl.concurrent.deadlock.DeadLockTest$$Lambda$1/1607521710.run(Unknown Source)
  at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

也能查看到死锁的状况

总结

生产环境死锁的检测,通常都是通过命令行的方式进行查看。

作者:小鱼儿-karl

原文链接:https://blog.csdn.net/qq_33249725/article/details/104267428

0 人点赞