Java Thread Dump 死锁分析

本文通过一个简单的demo介绍 Java通过Thread Dump进行死锁分析

1.测试代码

import java.util.concurrent.TimeUnit;
/**
 * 死锁分析
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();
        new Thread(new ThreadA(lockA,lockB)).start();
        new Thread(new ThreadB(lockA,lockB)).start();
    }
}

/**
 * 线程A
 */
class ThreadA implements Runnable{

    private Object lockA = null;
    private Object lockB = null;

    public ThreadA(Object a, Object b){
        this.lockA = a;
        this.lockB = b;
    }

    public void run() {
        synchronized (lockA) {
            System.out.println("ThreadA已经获得锁lockA" );
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ThreadA尝试获取锁lockB..." );
            synchronized (lockB) {
                System.out.println("ThreadA已经获得锁lockB" );
            }
        }
    }

}

/**
 * 线程B
 */
class ThreadB implements Runnable{

    private Object lockA = null;
    private Object lockB = null;

    public ThreadB(Object a, Object b){
        this.lockA = a;
        this.lockB = b;
    }
    public void run() {
        synchronized (lockB) {
            System.out.println("ThreadB已经获得锁lockB" );
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ThreadB尝试获取锁lockA..." );
            synchronized (lockA) {
                System.out.println("ThreadB已经获得锁lockA" );
            }
        }

    }

}
代码说明

定义了两个线程类ThreadA和ThreadB,以及两个锁对象lockA和lockB。
ThreadA获得锁lockA ,3秒后尝试获取锁lockB,
ThreadB获得锁lockB ,3秒后尝试获取锁lockA ,
而此时lockA以及lockB分别被ThreadA和ThreadB占用,因此两个线程相互等待对方释放锁,产生了死锁。

代码运行结果
ThreadA已经获得锁A
ThreadB已经获得锁B
ThreadA尝试获取锁B...
ThreadB尝试获取锁A...

2.获取Thread Dump

通过kill -3 [pid] 命令获取Thread Dump

➜  ~ jps
65090 Launcher
55986 KotlinCompileDaemon
65091 DeadLockDemo
65133 Jps
➜  ~ kill -3 65091

我是直接在idea运行的,所以可以在console中直接看到打印的Thread Dump信息:

ThreadA已经获得锁A
ThreadB已经获得锁B
ThreadA尝试获取锁B...
ThreadB尝试获取锁A...
2019-06-30 21:13:46
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=0x00007fbeb1837800 nid=0x5b03 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

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

"Thread-1" #12 prio=5 os_prio=31 tid=0x00007fbeb1836000 nid=0xa603 waiting for monitor entry [0x00007000065dd000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.berrymew.common.ThreadB.run(DeadLockDemo.java:68)
	- waiting to lock <0x000000076aeec848> (a java.lang.Object)
	- locked <0x000000076aeec858> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)

"Thread-0" #11 prio=5 os_prio=31 tid=0x00007fbeb08a9800 nid=0x5803 waiting for monitor entry [0x00007000064da000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.berrymew.common.ThreadA.run(DeadLockDemo.java:39)
	- waiting to lock <0x000000076aeec858> (a java.lang.Object)
	- locked <0x000000076aeec848> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)
	...##中间省略
	Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007fbeb1003818 (object 0x000000076aeec848, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007fbeb1006158 (object 0x000000076aeec858, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
	at com.berrymew.common.ThreadB.run(DeadLockDemo.java:68)
	- waiting to lock <0x000000076aeec848> (a java.lang.Object)
	- locked <0x000000076aeec858> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)
"Thread-0":
	at com.berrymew.common.ThreadA.run(DeadLockDemo.java:39)
	- waiting to lock <0x000000076aeec858> (a java.lang.Object)
	- locked <0x000000076aeec848> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.
...##后面省略

可以看到Thread Dump中明确的指出Found one Java-level deadlock,并且给出了死锁出现的位置。

3.其他获取Thread Dump的方式

除了kill -3 的方式,还可以使用jdk自带的工具获取:

  • jstack [pid]
    通过jstack命令可以直接在终端看到相关信息:
Java stack information for the threads listed above:
===================================================
"Thread-1":
	at com.berrymew.common.ThreadB.run(DeadLockDemo.java:68)
	- waiting to lock <0x000000076aeec848> (a java.lang.Object)
	- locked <0x000000076aeec858> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)
"Thread-0":
	at com.berrymew.common.ThreadA.run(DeadLockDemo.java:39)
	- waiting to lock <0x000000076aeec858> (a java.lang.Object)
	- locked <0x000000076aeec848> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.
  • jvisualvm
    通过图形化工具jvisualvm可以直观的看到死锁警告
    Java Thread Dump 死锁分析_第1张图片
    点击线程Dump可以看到具体信息
    Java Thread Dump 死锁分析_第2张图片

在高并发环境很容易产生死锁,我们可以通过如上方法灵活地定位死锁产生位置,解决问题。

注:运行环境Java8 linux/Unix

你可能感兴趣的:(Java)