Java死锁能被自动检测,但仅限于synchronized内置锁场景;JVM通过ThreadMXBean可检测此类死锁,却无法识别ReentrantLock等显式锁及wait/notify逻辑死锁。
Java死锁能被自动检测吗?能,但仅限于线程持有对象监视器锁(synchronized)的场景
Java 虚拟机本身不主动预防死锁,但在运行时可通过 ThreadMXBean 检测到部分死锁——前提是这些死锁涉及的是内置锁(即 synchronized 块/方法持有的 java.lang.Object 监视器锁)。JVM 无法检测基于 java.util.concurrent.locks.Lock(如 ReentrantLock)的死锁,除非你显式调用其 getHoldCount() 或启用 fairness + 配合外部监控。
常见错误现象:jstack -l 输出中出现 Found 1 deadlock.,但线上服务已卡住数分钟才被发现;或使用 VisualVM 查看线程状态时,多个线程长期处于 BLOCKED 状态,且堆栈显示互相等待对方持有的 monitor。
- 检测触发条件:至少两个线程,每个都持有一个锁并试图获取另一个线程持有的锁
-
ThreadMXBean.findDeadlockedThreads()返回非 null 数组即表示存在 synchronized 死锁 - 该 API 不扫描
Lock实现,也不覆盖wait()/notify()引发的逻辑死锁(例如线程 Await()在 obj1,线程 Bwait()在 obj2,双方都不notify())
如何用 ThreadMXBean 主动轮询检测 synchronized 死锁
适合嵌入监控 Agent 或健康检查端点。注意不要高频调用(建议间隔 ≥30 秒),否则可能因锁竞争影响性能。
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] deadlockedIds = bean.findDeadlockedThreads(); // 返回 null 表示无死锁
if (deadlockedIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(deadlockedIds, true, true);
for (ThreadInfo info : infos) {
System.out.println("Deadlocked thread: " + info.getThreadName());
System.out.println("Locked on: " + info.getLockName());
System.out.println("Blocked by: " + info.getLockOwnerName());
}
}
- 第二个参数
true表示采集线程堆栈,第三个true表示采集锁信息(包括持有者和等待者) - 若返回
deadlockedIds长度为 0,不代表绝对安全——可能是死锁尚未形成,或只涉及Lock类型 - 在容器化环境(如 Kubernetes)中,可将此逻辑封装为
/actuator/health子项,配合 Prometheus 抓取
jstack 和 jcmd 哪个更适合线上紧急排查?优先用 jcmd
jstack 在某些 JDK 版本(尤其是旧版 HotSpot)下会尝试对目标 JVM 全局 safepoint,导致应用暂停(STW),而 jcmd 更轻量、更可靠。