分析synchronized线程dump的核心是识别monitor锁的持有与等待关系:先搜“found one java-level deadlock”确认死锁,未命中则手动比对blocked线程的“locked ”和“waiting to lock ”地址是否交叉成环,并结合at xxx.java:行号验证加锁顺序颠倒。

分析 synchronized 相关的线程 Dump 日志,核心是识别线程是否因争抢 monitor 锁而阻塞,以及是否存在循环等待构成死锁。关键不在于看代码写了多少个 synchronized,而在于看 JVM 运行时谁持有了哪把锁、谁在等哪把锁。
synchronized 在 Dump 中的典型表现
Java 中用 synchronized 块或方法加锁时,JVM 会为每个对象关联一个 monitor(监视器)。在线程 Dump 里,这种锁行为会明确体现在线程状态和栈帧描述中:
-
线程状态为
BLOCKED (on object monitor):说明该线程正尝试进入synchronized代码块/方法,但目标对象的 monitor 已被其他线程持有,它正在排队等待 -
栈帧中出现
- waiting to lock:表示它卡在这行代码,等待获取指定地址的对象锁 -
同一栈帧中出现
- locked:说明该线程当前正持有这个对象锁(注意:locked行一定出现在它自己的调用栈里,不是别人写的) - 如果一个线程既
locked A又waiting to lock B,另一个线程刚好相反——就构成了死锁基础链
定位 synchronized 死锁的实操步骤
使用 jstack -l <pid></pid> 获取带锁信息的 Dump,然后按顺序检查:
- 直接搜索
Found one Java-level deadlock—— 如果存在,说明 JVM 已确认synchronized或ReentrantLock引发的循环等待 - 若未命中,手动扫描所有
BLOCKED (on object monitor)线程,逐个查看其waiting to lock和locked对象地址是否交叉成环 - 比对两个线程的锁地址是否完全一致(如
),大小写和数值必须严格相同 - 结合源码定位具体行号:Dump 中的
at xxx.java:23能快速指向加锁位置,重点看两处synchronized(obj)的传入对象是否顺序颠倒
常见干扰项与排除要点
不是所有阻塞都跟 synchronized 有关,需避免误判:
-
WAITING (parking)或TIMED_WAITING状态一般与Object.wait()、LockSupport.park()或线程池任务队列相关,不涉及 monitor 争抢 -
RUNNABLE但 CPU 飙高,大概率是无限循环或密集计算,和锁无关 - 多个线程同时
waiting to lock同一个地址,属于单点锁竞争激烈,不是死锁,但可能是性能瓶颈 - 只看到
waiting to lock却找不到对应线程的locked行?可能锁已被释放,或该线程已退出,此时需结合多次 Dump 对比时间差
辅助验证的小技巧
光看 Dump 有时不够,可配合运行时信息增强判断:
- 用
jstat -gc <pid></pid>查看是否频繁 GC 导致线程调度延迟,掩盖真实锁问题 - 用
top -H -p <pid></pid>找出高 CPU 的原生线程 ID(nid),再在 Dump 中用十六进制 nid 匹配线程,确认是不是它在死循环 - 在测试环境复现时,加 JVM 参数
-XX:+PrintConcurrentLocks,可让jstack -l输出更详细的锁持有关系 - 对疑似锁对象做内存分析:用
jmap -histo <pid></pid>查看该对象是否大量创建,或用 MAT 分析是否被意外长期引用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











