jstack -l 是最快速零依赖的死锁诊断方式,通过 jps -l 获取pid后执行 jstack -l pid > deadlock.log,搜索“found one java-level deadlock”定位死锁线程及锁等待闭环,并结合堆栈行号与锁对象地址分析交叉锁定问题。

获取进程 ID 并导出带锁信息的线程快照
先确认目标 Java 进程的 PID:
- 运行 jps -l,找到你的应用主类或 JAR 路径对应的数字(如 12345)
- 执行 jstack -l 12345 > deadlock.log —— -l 参数必须加,否则看不到 ReentrantLock 持有者和 monitor 详情
- 若进程无响应,可加 -F 强制抓取(慎用,可能短暂影响服务)
识别 jstack 输出中的死锁标志
打开生成的日志文件,直接搜索关键词:
- 开头或末尾出现 Found one Java-level deadlock:,说明 JVM 已自动检测到死锁
- 下面会列出所有卷入死锁的线程名,例如:
"Thread-A": waiting to lock (a java.lang.Object), which is held by "Thread-B"
"Thread-B": waiting to lock (a java.lang.Object), which is held by "Thread-A" - 注意每行末尾的 locked
和 waiting to lock 是否构成闭环(A 等 B 的锁,B 等 A 的锁)
结合堆栈定位具体代码行
死锁摘要下方会附上每个线程的完整调用栈:
- 查找类似 at com.example.Service.transfer(TransferService.java:42) 的源码行号
- 看该行是否为 synchronized(obj) { ... } 或 lock.lock() 调用
- 比对两个线程分别锁的对象(
地址),确认它们不是同一个实例,而是交叉锁定不同资源
辅助验证:用 jconsole 图形化确认
适合现场交互排查:
- 启动 jconsole,连接目标进程 → 切换到“线程”页签
- 点击 “检测死锁” 按钮,界面会高亮标出死锁线程
- 选中线程后,右侧显示堆栈;双击某行可跳转源码(需编译时保留调试信息)
- 关注下方“锁定监视器”区域,核对多个线程持有的对象类型和 hashCode 是否一致
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











