jstack排查synchronized死锁的核心是捕获带锁信息的线程快照并识别循环等待:先用jps -l获取PID,再执行jstack -l <pid> > deadlock.log,末尾“found one Java-level deadlock”区块会明确列出互相等待的线程、锁地址及阻塞源码行,结合代码验证加锁顺序不一致即可定位问题。

Java中用 jstack 排查 synchronized 引起的死锁,核心是捕获线程快照并识别“互相等待对方持有的锁”这一循环依赖关系。jstack 能自动检测并高亮这类死锁,关键在于正确执行命令、理解输出结构,并结合代码上下文定位问题行。
获取目标Java进程PID
先确认你的应用正在运行,再拿到它的进程ID:
- 在终端执行
jps -l,列出所有Java进程及其完整类名 - 找到你的主类(如
com.example.DeadLockTest)对应的数字ID,例如12345 - 若环境受限(如Docker容器内),可能需加
sudo或切换到应用运行用户执行
生成带锁信息的线程快照
仅用 jstack <pid> 可能漏掉关键锁持有细节,尤其对 synchronized 块:
- 务必加上
-l参数:jstack -l 12345 > deadlock.log -
-l会显示每个线程持有哪些 monitor(即 synchronized 锁对象)以及正在等待哪个 monitor - 如果进程已卡死无响应,仍可成功执行该命令——jstack 读取的是 JVM 运行时内存状态,不依赖应用逻辑继续执行
快速识别死锁摘要和线程栈
打开 deadlock.log,直接拉到文件末尾,找以 “found one Java-level deadlock” 开头的区块:
立即学习“Java免费学习笔记(深入)”;
- 它会明确列出参与死锁的线程名(如
"thread-0","thread-1") - 指出谁在等谁的锁:
waiting to lock <0x00000000d5f6e3a0>,而该锁被另一个线程held by "thread-1" - 紧接着的
Java stack information部分会显示每个线程阻塞在源码哪一行,例如:
at com.example.DeadLockTest.lambda$main$0(DeadLockTest.java:17)
这说明第17行是synchronized(lock1)或synchronized(lock2)的入口点
对照代码验证加锁顺序冲突
死锁本质是锁获取顺序不一致。看到 jstack 输出后,回到源码重点检查:
- 线程A是否先锁
lock1再尝试锁lock2 - 线程B是否先锁
lock2再尝试锁lock1 - 两个
synchronized块是否跨方法、跨对象、且无统一约定顺序 - 注意:
synchronized(this)、synchronized(staticMethod)(类锁)、synchronized(new Object())都算不同锁对象,都可能卷入死锁


















