jstack排查死锁和线程阻塞的关键在于从输出中快速识别真实问题:末尾自动检测死锁,BLOCKED线程需结合锁地址定位持有者,再联动top和nid匹配高CPU线程。

用 jstack 排查死锁和线程阻塞,关键不是“会不会运行命令”,而是能否从输出中快速识别真实问题。它不依赖日志或代码修改,只要进程还在运行,就能抓取当前线程快照——这是线上诊断最直接、最低侵入的方式。
获取进程 PID 并生成带锁信息的线程快照
先确认目标 Java 进程 ID:
- 执行 jps -l 列出所有 Java 进程,找到你的应用(如 12345 com.example.MyApplication)
- 用 jstack -l 12345 > thread_dump.txt 导出完整快照,“-l”必须加,否则 ReentrantLock 等显式锁可能不显示持有者(JDK 8u60+ 才稳定支持)
- 若进程已无响应,可尝试 jstack -F -l 12345 强制获取;容器环境注意以应用同用户身份执行,避免权限拒绝
定位死锁:直接看末尾的自动检测结果
jstack 会在文件末尾明确标出死锁,无需逐行扫描:
- 搜索关键词 Found one Java-level deadlock 或 Deadlock detected
- 下面会列出相互等待的线程链,例如:
"Thread-A": waiting to lock <0x000000076b0a1111>, which is held by "Thread-B"
"Thread-B": waiting to lock <0x000000076b0a2222>, which is held by "Thread-A" - 对应线程的栈帧里会标注 - locked <0x...>(已持锁)和 - waiting to lock <0x...>(正等待),两者的锁地址刚好互换,就是典型死锁
识别线程阻塞:重点看 BLOCKED 状态与锁竞争点
阻塞不等于死锁,但常是性能瓶颈源头:
立即学习“Java免费学习笔记(深入)”;
- 搜索 java.lang.Thread.State: BLOCKED (on object monitor),这类线程正在等 synchronized 锁
- 检查其栈顶方法是否在进入 synchronized 块/方法前卡住,例如:
at com.example.Service.updateOrder(Service.java:42)
- waiting to lock <0x000000076b0a3333> (a java.lang.Object) - 再全局搜索该锁地址 <0x000000076b0a3333>,找到哪个线程正持有它(有 - locked <0x...> 标记),它的调用栈就是阻塞源头
- 常见阻塞场景:锁粒度太大、慢 SQL 持有锁过久、IO 阻塞未超时、线程池满导致任务排队等待 worker
辅助验证:结合操作系统级线程匹配高 CPU 或长时间挂起
单看 jstack 有时不够,需联动定位真实消耗点:
- 在 Linux 上执行 top -Hp 12345 查看该 JVM 内各线程的 CPU 占用,记下高消耗线程的十进制 PID
- 将该 PID 转为十六进制(如 12345 → 0x3039),回到 thread_dump.txt 中搜索 nid=0x3039,即可锁定具体是哪个 Java 线程在疯狂运算
- 若发现大量线程处于 TIMED_WAITING 且堆栈停在 java.net.SocketInputStream.socketRead0 或 org.apache.tomcat.util.net.NioEndpoint$Poller.run,可能是外部依赖超时未设或连接池耗尽


















