什么是Thread Dump?

Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread dump略有不同,但是大多都提供了当前活动线程的快照,及JVM中所有Java线程的堆栈跟踪信息,堆栈信息一般包含完整的类名及所执行的方法,如果可能的话还有源代码的行数。

可以用Thread Dump 和jstack命令来查看死锁情况。

  1. 抓的是JVM进程,也就能打出所有进程中的线程
  2. 能在各种操作系统下使用
  3. 能在各种Java应用服务器下使用
  4. 可以在生产环境下使用而不影响系统的性能
  5. 可以将问题直接定位到应用程序的代码行上

怎么使用thread Dump?

jstack

jstack 是一个抓取 thread dump 文件的有效的命令行工具,它位于 JDK 目录里的 bin 文件夹下(JDK_HOME\bin),以下是抓取 dump 文件的命令: 

jstack -l <pid> > <file-path>

说明: pid: Java 应用的进程 id ,也就是需要抓取 dump 文件的应用进程 id。 file-path: 保存 dump 文件的路径。 示例: 

jstack -l 37320 > /opt/tmp/threadDump.txt

上面的例子演示了用 jstack 生成 dump 文件到 /opt/tmp/threadDump.txt 目录下。 另外,从 Java5 开始,jstack 被包含进了 jdk 当中,如果你使用老版本的 jdk,要考虑使用其他方式。

Kill -3

处于安全方面的考虑,有一部分生产环境的机器只包含 JRE 环境,因此就不能使用 jstack 工具了,在这种情况下,我们可以使用 kill -3 的方式:

kill -3 <pid>

说明: pid: Java 应用的进程 id ,也就是需要抓取 dump 文件的应用进程 id 。

示例: 

kill -3 37320

当使用 kill -3 生成 dump 文件时,dump 文件会被输出到标准错误流。假如你的应用运行在 tomcat 上,dump 内容将被发送到/logs/catalina.out 文件里。

分析获取的文件

下面是获取的文件的一个例子,首先打印出线程名字,编号,是否是守护线程,tid的值,还有一些我们不需要知道的信息。中间部分是当前的状态,然后是栈的调用轨迹,也就是栈帧的情况。

"ajp-nio-8009-ClientPoller-0" #46 daemon prio=5 os_prio=0 tid=0x00007f7650502000 nid=0x93c runnable [0x00007f761e8e7000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000000d9946e68> (a sun.nio.ch.Util$2)
    - locked <0x00000000d9946e58> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000000d9946e10> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:702)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

"ajp-nio-8009-exec-10" #45 daemon prio=5 os_prio=0 tid=0x00007f76504f0800 nid=0x93b waiting on condition [0x00007f761e9e8000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000d9947028> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
    at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103)
    at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None