jstack

返回 JDK 工具

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"

也可用 jconsolejcmdThread.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

若多次快照同一线程栈帧完全相同,说明线程长时间阻塞在该位置。


相关链接

  • jcmd — 可用 Thread.print 命令替代 jstack,功能更集中
  • jconsole — 图形界面死锁检测
  • JVM — 线程模型与内存结构
  • JUC — 锁、阻塞队列等并发原语的线程状态背景