jstack 可快速识别 Java 线程死锁,需先用 jps -l 或 ps -ef | grep java 获取 PID,再执行 jstack -F -l > thread_dump.log 抓取带锁详情的线程快照,多次采集后搜索“Found 1 deadlock.”定位死锁线程链。

Java 中线程死锁可以通过 jstack 快速识别,关键在于捕获到发生死锁时的 JVM 线程快照,并从中定位互相持有和等待锁的线程链。
确认进程 PID 并执行 jstack 抓取
先用 jps -l 或 ps -ef | grep java 找到目标 Java 进程的 PID。然后运行:
-
jstack -l:加> thread_dump.log -l参数可输出详细的锁信息(包括java.util.concurrent中的显式锁),这对排查 ReentrantLock 死锁至关重要 - 若进程无响应,可尝试加
-F强制 dump(需有相应权限):jstack -F -l - 生产环境建议一次性多抓几次(如间隔 2 秒连抓 3 次),避免偶然性;死锁通常会在多次 dump 中稳定复现
快速识别死锁的关键特征
jstack 输出中,JVM 会自动检测并标出死锁(如果存在),直接搜索关键词:
- 查找
Found 1 deadlock.或类似提示——这是最直接信号,下面会紧跟参与死锁的线程列表 - java.lang.Thread.State: BLOCKED (on object monitor) 状态,并关注其 waiting to lock 和 locked ownable synchronizers 两段
- 比对线程 A 持有锁 L1 却等待 L2,线程 B 持有 L2 却等待 L1 —— 典型循环等待结构
分析锁对象与代码位置
从堆栈中提取关键线索定位问题代码:
- 看
locked和waiting to lock后面的十六进制地址,相同地址代表同一把锁(注意:不同次 dump 中地址可能变化,但同一次 dump 内可比对) - 顺着线程堆栈往上翻,找到最靠近业务逻辑的
at com.xxx.YourClass.method(YourClass.java:xx)行,那里就是加锁/请求锁的位置 - 若涉及
ReentrantLock,留意locked ownable synchronizer下的java.util.concurrent.locks.ReentrantLock$NonfairSync及其持有者线程名
辅助验证与避坑提醒
光靠一次 jstack 不一定够,注意这些实际细节:
- 死锁可能只在特定并发路径下触发,dump 时未处于死锁态则不会被 jstack 标出;此时需结合应用日志、监控(如线程数持续增长、请求超时突增)综合判断
- 不要混淆死锁(Deadlock)和长阻塞(如数据库慢查询、网络 IO 卡住);后者线程状态常为
TIMED_WAITING或WAITING,且无循环等待锁关系 - 使用
jstack -l是必须项,不加可能漏掉java.util.concurrent锁的持有关系,导致误判为“无死锁”
只要 dump 时机得当、关注锁地址与堆栈上下文,jstack 定位死锁并不复杂,但容易因忽略 -l 参数或未连续采样而错过关键证据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











