Java线程转储 – VisualVM, jstack, kill -3, jcmd
Java线程转储是JVM中所有活动线程的列表。
Java线程转储
Java线程转储在分析应用程序瓶颈和死锁情况方面非常有帮助。在这里,我们将学习多种生成Java程序的线程转储的方法。这些说明适用于*nix操作系统,但在Windows中,步骤可能会有些不同。
-
- VisualVM Profiler:如果你正在分析应用程序的速度慢问题,你必须使用一个分析器。我们可以使用VisualVM Profiler轻松地为任何进程生成线程转储。你只需右键点击运行中的进程,然后点击“Thread Dump”选项来生成它。
-
- jstack:Java自带了jstack工具,通过它我们可以为一个Java进程生成线程转储。这是一个两步骤的过程。
使用ps -eaf | grep java命令找到Java进程的PID。
运行jstack工具,使用jstack PID命令将线程转储的输出生成到控制台,你可以使用命令“jstack PID >> mydumps.tdump”将线程转储输出追加到文件中。
我们可以使用kill -3 PID命令来生成线程转储。这与其他生成线程转储的方式略有不同。当发出kill命令时,线程转储将生成到程序的标准输出中。所以如果是一个带有控制台作为标准输出的Java程序,线程转储将打印在控制台上。如果Java程序是一个带有catalina.out作为标准输出的Tomcat服务器,那么线程转储将会生成到文件中。
Java 8引入了jcmd实用程序。如果你使用的是Java 8或更高版本,你应该使用它而不是jstack。使用jcmd生成线程转储的命令是jcmd PID Thread.print。
以下是生成Java线程转储的四种不同方法。通常我更喜欢使用jstack或jcmd命令来生成线程转储并进行分析。请注意,无论您选择哪种方法,线程转储始终是相同的。
Java线程转储示例
在我的最后一篇博文中,我解释了Java计时器,这里是同一程序生成的线程转储。
2012-12-26 22:28:39
Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.5-b02 mixed mode):
"Attach Listener" daemon prio=5 tid=0x00007fb7d8000000 nid=0x4207 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Timer-0" daemon prio=5 tid=0x00007fb7d4867000 nid=0x5503 waiting on condition [0x00000001604d9000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.Olivia.threads.MyTimerTask.completeTask(MyTimerTask.java:19)
at com.Olivia.threads.MyTimerTask.run(MyTimerTask.java:12)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
"Service Thread" daemon prio=5 tid=0x00007fb7d482c000 nid=0x5303 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=5 tid=0x00007fb7d482b800 nid=0x5203 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=5 tid=0x00007fb7d4829800 nid=0x5103 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=5 tid=0x00007fb7d4828800 nid=0x5003 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=5 tid=0x00007fb7d4812000 nid=0x3f03 in Object.wait() [0x000000015fd26000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000140a25798> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x0000000140a25798> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)
"Reference Handler" daemon prio=5 tid=0x00007fb7d4811800 nid=0x3e03 in Object.wait() [0x000000015fc23000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000140a25320> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x0000000140a25320> (a java.lang.ref.Reference$Lock)
"main" prio=5 tid=0x00007fb7d5000800 nid=0x1703 waiting on condition [0x0000000106116000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.Olivia.threads.MyTimerTask.main(MyTimerTask.java:33)
"VM Thread" prio=5 tid=0x00007fb7d480f000 nid=0x3d03 runnable
"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007fb7d500d800 nid=0x3503 runnable
"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007fb7d500e000 nid=0x3603 runnable
"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007fb7d5800000 nid=0x3703 runnable
"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007fb7d5801000 nid=0x3803 runnable
"GC task thread#4 (ParallelGC)" prio=5 tid=0x00007fb7d5801800 nid=0x3903 runnable
"GC task thread#5 (ParallelGC)" prio=5 tid=0x00007fb7d5802000 nid=0x3a03 runnable
"GC task thread#6 (ParallelGC)" prio=5 tid=0x00007fb7d5802800 nid=0x3b03 runnable
"GC task thread#7 (ParallelGC)" prio=5 tid=0x00007fb7d5803800 nid=0x3c03 runnable
"VM Periodic Task Thread" prio=5 tid=0x00007fb7d481e800 nid=0x5403 waiting on condition
JNI global references: 116
线程转储是所有线程的列表,每个条目按出现顺序显示线程的信息,其中包括以下内容。
-
- 线程名称:线程的名称
-
- 线程优先级:线程的优先级
-
- 线程ID:表示线程的唯一ID
-
- 线程状态:提供当前线程的状态,例如可运行,等待,阻塞。在分析死锁时,查看被阻塞的线程以及它们尝试获取锁定的资源。
- 线程调用栈:提供线程的关键堆栈信息。这是我们可以看到线程获得的锁以及它是否正在等待任何锁的地方。
这就是有关Java线程转储的所有内容。