jstack -l 是诊断 jvm 线程阻塞/死锁的核心命令,需结合锁地址(locked/waiting to lock)、线程状态(blocked/waiting/runnable)及调用栈上下文精准定位问题源头。

用 jstack 监控和分析 JVM 线程阻塞与等待,核心是抓准状态特征、锁地址关联和调用栈上下文。不需要改代码、不重启服务,一次命令就能看到线程“卡在哪、等什么、被谁拦着”。
先拿到带锁信息的线程快照
只执行 jstack <pid></pid> 往往漏掉关键线索——必须加 -l 参数:
-
jps -l找出目标 Java 进程 PID -
jstack -l <pid> > dump.log</pid>重定向保存,避免终端刷屏丢失内容 -
-l是关键:它会显示locked和waiting to lock,这是判断阻塞和死锁的唯一依据
重点识别三类状态及其真实含义
别只看状态名,要结合栈帧和锁标记一起读:
-
BLOCKED:线程在争抢 synchronized 锁,栈顶行通常标有
- waiting to lock;顺着这个地址全局搜索,一定能找到另一个线程的- locked—— 那就是阻塞源头 -
WAITING / TIMED_WAITING:不是“空闲”,而是主动挂起。常见于
Object.wait()、Condition.await()或LockSupport.park();看栈顶方法是否合理,比如线程池 worker 停在parking to wait for是正常,但业务线程停在wait()却没被唤醒,就可能泄露资源 -
RUNNABLE 但 CPU 高:可能陷入死循环或密集计算;配合
top -H -p <pid></pid>查出高 CPU 的 native 线程 tid,转成十六进制后在 dump 中搜nid=0x...,直接定位 Java 栈
快速定位阻塞链和死锁
人工扫全量日志效率低,用关键词精准过滤:
- 搜
Found one Java-level deadlock:jstack 自动检测,结尾会列出互相等待的线程对,例如:"Thread-A": waiting to lock , which is held by "Thread-B""Thread-B": waiting to lock , which is held by "Thread-A" - 搜
java.lang.Thread.State: BLOCKED,再用-A 5 -B 3向后向前多看几行,看清它卡在哪个类哪一行、等的是什么锁 - 搜锁地址,比如
,确认只有一个线程locked它,其余都是waiting to lock—— 如果多个线程都 claim 持有同一把锁,说明日志采集时序有问题,需重采
结合操作系统验证线程行为
jstack 是静态快照,单靠它容易误判。需要联动验证:
- 发现大量线程 BLOCKED,但应用响应尚可?可能是瞬时竞争,用
jstack -l <pid></pid>多采几次(间隔 2–3 秒),看是否持续存在 - 怀疑某线程长期 WAITING 导致资源堆积?查该线程是否频繁创建对象,再用
jmap -histo <pid></pid>看对应类实例数是否持续增长 - 线程名称含明显业务标识(如
OrderProcessor-*)且数量不断上升?大概率存在线程泄漏,不是单纯阻塞问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











