jstack可快速识别java线程死锁,关键是查看输出末尾“found 1 deadlock”区块,它由jvm自动检测并高亮,明确列出互相等待的线程、锁地址及阻塞源码行。

Java 线程死锁可以通过 jstack 快速识别,关键是看它是否自动检测并高亮输出“Found 1 deadlock”段落——这是最直接的死锁信号。
运行 jstack 获取线程快照
在 Java 进程仍在运行时,用 jstack [pid] 抓取当前所有线程堆栈。确保使用与目标 JVM 相同版本的 JDK 提供的 jstack(例如:JDK 8 的 jstack 不能可靠分析 JDK 17 的进程)。
- Linux/macOS 下先用
jps -l或ps aux | grep java找到 Java 进程 PID - 执行
jstack -l <pid> > thread_dump.txt</pid>保存完整输出(-l参数可显示锁信息,对排查死锁很重要) - 如果进程无响应,可加
-F强制 dump(需 root 权限或进程属主权限)
定位 “Found 1 deadlock” 区块
jstack 在检测到死锁时,会在输出末尾单独生成一个清晰区块,标题就是 Found 1 deadlock(可能为多个,如 Found 2 deadlocks)。这个区块不依赖人工分析,是 JVM 内置死锁检测器触发的结果。
- 该区块会列出所有卷入死锁的线程名、状态(BLOCKED)、正在等待的锁(waiting to lock)和已持有的锁(locked ownable synchronizer)
- 每条线程行下方会给出其阻塞源头,例如:
java.lang.Thread.State: BLOCKED (on object monitor)后紧跟着waiting to lock - 对比各线程的
waiting to lock和locked ownable synchronizer地址,能直观看出 A 等 B 的锁、B 等 A 的锁的循环依赖
对照线程堆栈定位问题代码
找到死锁线程名(如 "Thread-1")后,回到 jstack 输出前半部分,搜索该线程的完整堆栈,重点关注 synchronized 方法/代码块或 ReentrantLock.lock() 调用位置。
- 看堆栈最顶部几行,通常能定位到具体类、方法、行号,例如:
at com.example.Service.process(Service.java:42) - 若用的是显式锁(
ReentrantLock),注意lock()调用点及未配对unlock()的风险;若用 synchronized,检查嵌套锁顺序是否一致 - 常见模式:两个线程以不同顺序获取同一组锁(如线程1先锁 A 再锁 B,线程2先锁 B 再锁 A)
验证与规避建议
仅靠一次 jstack 只能确认“此刻存在死锁”,但无法判断是否已恢复(有些死锁可能短暂发生又解开)。建议结合多次 dump 或添加 JVM 参数增强可观测性。
- 启动时加
-XX:+PrintConcurrentLocks(JDK 6+)可在 Ctrl+\ 或jstack -l时额外打印 java.util.concurrent 锁信息 - 生产环境可配置定时采集线程快照(如每 30 秒一次),便于回溯死锁发生时间点
- 预防上统一锁顺序、使用
tryLock(timeout)设超时、避免锁内调用外部方法,都是有效手段
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











