Java 线程转储 - VisualVM、jstack、kill -3、jcmd
Java 线程转储是 JVM 中所有活动线程的列表。
Java 线程转储
Java 线程转储对于分析应用程序瓶颈和死锁情况非常有用。在这里,我们将学习为 Java 程序生成线程转储的多种方法。这些说明适用于 *nix 操作系统,但在 Windows 中,步骤可能略有不同。
- VisualVM Profiler:如果您正在分析应用程序的运行速度,则必须使用分析器。我们可以非常轻松地使用 VisualVM Profiler 为任何进程生成线程转储。您只需右键单击正在运行的进程,然后单击“线程转储”选项即可生成它。
- jstack:Java 附带jstack工具,通过它可以为 Java 进程生成线程转储。这是一个两步过程。
ps -eaf | grep java
使用命令找出 java 进程的 PID- 运行 jstack 工具以
jstack PID
将线程转储输出生成到控制台,您可以使用命令“jstack PID >> mydumps.tdump
”将线程转储输出附加到文件
- 我们可以使用
kill -3 PID
命令来生成线程转储。这与其他生成线程转储的方法略有不同。发出 kill 命令时,会在程序的 System out 中生成线程转储。因此,如果是控制台为 system out 的 Java 程序,则线程转储将打印在控制台上。如果 Java 程序是系统输出为 的 Tomcat 服务器catalina.out
,则线程转储将在文件中生成。 - Java 8 引入了
jcmd
实用程序。如果您使用的是 Java 8 或更高版本,则应使用它而不是 jstack。使用 jcmd 生成线程转储的命令是jcmd PID Thread.print
。
以上是 Java 中生成线程转储的四种不同方法。通常我更喜欢使用 jstack 或 jcmd 命令来生成线程转储并进行分析。请注意,无论您选择哪种方式,线程转储始终都是相同的。
Java 线程转储示例
在我的上一篇文章中,我解释了java Timer,这里是为同一程序生成的线程转储。
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.journaldev.threads.MyTimerTask.completeTask(MyTimerTask.java:19)
at com.journaldev.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.journaldev.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
线程转储是所有线程的列表,每个条目显示有关线程的信息,其中包括按出现顺序排列的以下内容。
- 线程名称:线程的名称
- 线程优先级:线程的优先级
- Thread ID:表示线程的唯一ID
- 线程状态:提供当前线程状态,例如 RUNNABLE、WAITING、BLOCKED。分析死锁时,查找被阻塞的线程以及它们试图获取锁的资源。
- 线程调用堆栈:提供线程的重要堆栈信息。在这里,我们可以查看线程获取的锁以及它是否正在等待任何锁。
这就是 Java 中的线程转储的全部内容。