杰瑞科技汇

Linux下如何查看Java线程详情?

jstack (最常用、最标准)

jstack 是 JDK 自带的工具,专门用于生成 Java 虚拟机当前时刻的线程快照,这是分析线程问题(如死锁、CPU 100%)最核心、最可靠的方法。

Linux下如何查看Java线程详情?-图1
(图片来源网络,侵删)

找到 Java 进程的 PID

你需要知道你要分析的 Java 进程的进程 ID (PID)。

# 方法1: 使用 ps 命令
ps -ef | grep java
# 方法2: 使用 jps 命令 (推荐,只显示 Java 进程)
jps -l

假设你找到的 PID 是 12345

使用 jstack 生成线程快照

# 基本用法
jstack <PID> > thread_dump.txt
# 示例
jstack 12345 > thread_dump_12345.txt

这会在当前目录下生成一个 thread_dump.txt 文件,里面包含了该 JVM 中所有线程的详细信息。

分析 jstack 输出

jstack 的输出非常丰富,关键信息如下:

Linux下如何查看Java线程详情?-图2
(图片来源网络,侵删)
  • 线程状态:每个线程都有一个状态,如 RUNNABLE (运行中)、WAITING (等待)、TIMED_WAITING (定时等待)、BLOCKED (阻塞)。
  • 线程名"main", "http-nio-8080-exec-1" 等。
  • 线程 IDnid,即 Native ID,对应到 Linux 线程的 LWP ID。
  • 栈跟踪:最关键的部分,显示了线程执行到的方法调用路径,帮你定位问题代码。

示例分析:

# 假设我们用 jstack 生成的文件内容如下 (部分摘录)
"main" #1 prio=5 os_prio=0 tid=0x00007f8c3400b800 nid=0x5a03 waiting on condition [0x00007f8c5a2fe000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000d1bf3ef0> (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:2032)
        at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)
        at com.example.MyMain.run(MyMain.java:25)
        at java.lang.Thread.run(Thread.java:748)
"http-nio-8080-exec-1" #12 prio=5 os_prio=0 tid=0x00007f8c34012800 nid=0x5a1c runnable [0x00007f8c5a0fd000]
   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 <0x00000000d1bf5c50> (a java.lang.Object)
        at java.io.InputStreamReader.read(InputStreamReader.java:181)
        at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:226)
        ... (更多框架调用)

解读:

  • 线程 main:
    • 状态是 WAITING
    • 它在 ArrayBlockingQueue.take() 方法上等待,说明它在从一个队列中获取数据,如果队列为空,它就会一直等待,这是正常的行为。
  • 线程 http-nio-8080-exec-1:
    • 状态是 RUNNABLE,表示它正在运行。
    • 它的栈顶是 java.net.SocketInputStream.socketRead0,说明它正在等待从网络 socket 读取数据,这也是一个正常的工作线程状态。

查找问题:

  • 查找死锁jstack 会自动检测死锁,并在输出文件的开头明确报告。
    • "Found one Java-level deadlock:"
  • 查找 CPU 高占用:找到状态为 RUNNABLE 的线程,观察其栈跟踪,如果栈顶总是在一个循环或计算密集的方法中(MyHeavyComputation.doCalc()),那这个线程很可能就是导致 CPU 100% 的元凶。

top / htop + H (实时监控)

如果你只是想快速看一下哪个 Java 线程占用了大量 CPU,而不需要完整的栈跟踪,这个方法非常高效。

Linux下如何查看Java线程详情?-图3
(图片来源网络,侵删)

使用 top 命令

top -p <PID>

top -p 12345

  • H 键,top 会切换到线程视图。
  • 你会看到进程下的所有线程,找到 CPU 使用率最高的那个线程。
  • 记下它的 ID (PID 列下的值,这个是 Linux 线程 ID,也叫 LWP)。

将线程 ID 转换为十六进制

jstack 输出中的 nid 是十六进制的 Linux 线程 ID,所以你需要将上一步得到的十进制 ID 转换为十六进制。

# 假设 top 中看到的 CPU 占用最高的线程 ID 是 23109
printf "%x\n" 23109
# 输出可能是 5a95

jstack 输出中查找

打开之前用 jstack 生成的 thread_dump.txt 文件,搜索 nid=0x5a95,就能找到这个高 CPU 线程的完整调用栈。

htop 的优势:

htoptop 更现代、更易用。

  • 启动 htop 后,直接选中你的 Java 进程。
  • F2H (取决于版本) 进入设置,确保 "Tree view" 和 "Hide userland threads" 是关闭的。
  • F5 切换到树状视图。
  • 再次按 F5 可以展开/折叠进程,看到其下的线程。
  • 直接按 H 就可以显示/隐藏线程视图,找到高 CPU 线程后,直接按 c 可以查看其完整的命令行,比 top 更方便。

JConsole / VisualVM (图形化界面)

如果你更喜欢图形化工具,并且可以连接到目标 JVM,JConsole 和 VisualVM 是非常好的选择,它们通常随 JDK 一起安装。

启动工具

# 启动 VisualVM (功能更强大)
jvisualvm
# 或者启动 JConsole
jconsole

连接到 JVM

启动后,工具会自动扫描本机所有运行的 Java 进程,双击你要连接的进程。

查看线程

连接成功后,在左侧选择 “线程” (Threads) 标签页。

  • 线程监控:你可以看到所有线程的状态、CPU 时间等。
  • 线程 dump:工具栏上有一个“线程 Dump”按钮,点击它就能生成当前时刻的线程快照,效果和 jstack 一样,但是在图形界面里查看,更直观。
  • 死锁检测:如果发生死锁,图形界面会有非常明显的提示。

优点

  • 图形化,直观易懂。
  • 可以实时监控线程状态变化。
  • VisualVM 还可以分析堆内存、CPU 分析等,功能非常强大。

缺点

  • 需要图形界面支持(例如通过 X11 转发,或者直接在服务器上运行桌面环境)。
  • 对于生产环境,通常不允许开放图形端口,所以更常用于本地开发或测试环境。

总结与对比

方法 优点 缺点 适用场景
jstack 标准、强大、无图形依赖,输出详细,是分析问题的金标准。 需要两步操作(jps + jstack),分析文本需要一定经验。 生产环境问题排查(死锁、CPU飙高、线程hang住)的首选。
top/htop 快速、实时,能迅速定位到高CPU的线程。 无法直接看到线程调用栈,需要配合 jstack 深入分析。 快速初步定位CPU问题,缩小排查范围。
JConsole/VisualVM 图形化界面,直观,可实时监控,功能全面(内存、CPU等)。 需要图形环境,对生产环境不友好,可能影响性能。 本地开发调试测试环境的日常监控和问题分析。

推荐工作流程:

  1. 发现异常:通过 tophtop 或监控平台发现某个 Java 进程 CPU 占用很高。
  2. 定位线程:使用 top -Hhtop 找到占用 CPU 最高的那个 Linux 线程 ID (LWP)。
  3. 转换并分析:将该 LWP ID 转为十六进制,然后用 jstack <PID> > dump.txt 生成快照,在文件中搜索 nid=<十六进制ID>,查看其调用栈,定位问题代码。
  4. 深入分析:如果问题复杂,可以使用 VisualVM 连接进行更全面的分析。
分享:
扫描分享到社交APP
上一篇
下一篇