jstack
jstack 是 JDK 内置的线程快照工具,可打印目标 JVM 进程中所有线程的当前栈帧,是排查 CPU 占用高、死锁、线程阻塞等问题的首选工具。
基本用法
# 对指定 pid 打印线程快照(Thread Dump)
jstack <pid>
# 输出到文件(便于对比分析)
jstack <pid> > thread-dump-$(date +%s).txt
# 强制输出(-F):进程无响应时使用
jstack -F <pid>
# 同时输出 Java 和 Native 帧(-m)
jstack -m <pid>快速找 pid
# 列出所有 Java 进程
jps -l
# 或者
ps aux | grep java输出结构
"main" #1 prio=5 os_prio=0 tid=0x... nid=0x1234 waiting on condition [0x...]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.example.Main.run(Main.java:42)
"http-nio-8080-exec-1" #25 daemon prio=5 os_prio=0 tid=0x... nid=0x2345 runnable [0x...]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.read(SocketInputStream.java:150)
...
每段线程信息包含:
| 字段 | 说明 |
|---|---|
| 线程名 | 如 "main"、"http-nio-8080-exec-1" |
#N | 线程 ID(JVM 内部) |
nid | 操作系统线程 ID(16 进制),可与 top -Hp 对应 |
Thread.State | 线程状态(见下表) |
| 栈帧 | 当前调用栈 |
线程状态速查
| 状态 | 含义 | 排查方向 |
|---|---|---|
RUNNABLE | 正在运行或等待 CPU | 高 CPU 时重点关注 |
BLOCKED | 等待 Monitor 锁 | 锁竞争、死锁 |
WAITING | 无限等待(wait()、park()) | 等待通知或信号 |
TIMED_WAITING | 限时等待(sleep()、wait(ms)) | 通常正常,过多则警惕 |
TERMINATED | 已结束 | 无需关注 |
死锁检测
jstack 会自动检测死锁并在输出末尾打印:
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000... (object 0x..., a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000... (object 0x..., a java.lang.Object),
which is held by "Thread-1"
也可用 jconsole 或 jcmd(Thread.print)触发同样的检测。
CPU 占用高排查流程
1. 找出 CPU 高的线程 OS pid
top -Hp <java-pid> # Linux
2. 将 OS pid 转为 16 进制
printf '%x\n' <os-tid>
3. jstack 抓取快照,搜索该 nid
jstack <pid> | grep -A 30 "nid=0x<hex>"
4. 分析对应线程的栈帧
多次快照对比
单次快照只反映瞬间状态,间隔数秒抓多次可判断线程是否卡住:
for i in 1 2 3; do
jstack <pid> > dump-$i.txt
sleep 3
done若多次快照同一线程栈帧完全相同,说明线程长时间阻塞在该位置。