死锁发生的四个必要条件缺一不可:互斥、请求与保持、不可剥夺、循环等待;其中互斥不可破,后三者可通过固定锁顺序、避免嵌套错序加锁等方式打破。

死锁发生的四个必要条件缺一不可
Java里发生死锁,不是因为“锁用多了”,而是同时满足了四个经典条件:互斥、请求与保持、不可剥夺、循环等待。只要其中任意一个被打破,死锁就不会出现——但注意,互斥是锁机制的基础,不能也不该被破坏;真正可操作的是后三个。
-
请求与保持:线程拿着锁1,又去申请锁2,而锁2正被别人拿着——这是最常写错的逻辑,比如转账方法里先锁账户A再锁账户B,但并发时另一线程反着来 -
不可剥夺:Java中没有强制抢锁的机制(synchronized和ReentrantLock都不支持),所以一旦持有就只能等它自己释放 -
循环等待:本质是锁获取顺序不一致。两个线程对同一组对象加锁,但顺序相反,比如线程1:lockA → lockB,线程2:lockB → lockA,只要时间点卡得准,立刻卡死
最典型的代码死锁场景:嵌套 synchronized 错序
下面这段代码在 JDK 8+ 上跑几次大概率复现死锁,不是偶然,是设计缺陷:
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
<p>// 线程1
synchronized (lock1) {
System.out.println("T1: got lock1");
Thread.sleep(10);
synchronized (lock2) { /<em> 等 lock2 → 可能被T2占着 </em>/ }
}</p><p>// 线程2<br />
synchronized (lock2) {
System.out.println("T2: got lock2");
Thread.sleep(10);
synchronized (lock1) { /<em> 等 lock1 → 可能被T1占着 </em>/ }
}关键点在于:Thread.sleep(10) 不是“为了演示”才加的,而是模拟真实业务中锁持有时间不可控——哪怕只差几毫秒,就足以让两个线程各自拿到一把锁、再一起卡住。
为什么 ReentrantLock.tryLock() 也救不了乱序加锁?
有人以为换成 ReentrantLock + tryLock(long, TimeUnit) 就安全了,其实不然。超时只是避免无限等待,但没解决根本问题:如果两个线程都成功拿到第一把锁,又几乎同时调用 tryLock() 争第二把,失败后若不做统一回退(比如释放已持锁并重试),反而可能引发活锁或资源浪费。
立即学习“Java免费学习笔记(深入)”;
- 正确做法不是“加 tryLock”,而是“固定锁顺序”:比如按对象哈希值排序,始终先锁
Math.min(lockA.hashCode(), lockB.hashCode())对应的锁 -
tryLock()的超时时间设太短(如 1ms)会导致频繁重试;设太长(如 5s)又失去响应性——它只是逃生通道,不是避坑指南 - 注意:
ReentrantLock默认不支持公平模式,高并发下即使顺序一致,也可能因调度抖动导致实际加锁次序偏移
排查死锁比预防更难,但 jstack 是免费救命稻草
线上服务突然卡住?别急着重启,先用 jps 找到 Java 进程 ID,再执行 jstack <pid></pid>。如果真有死锁,输出末尾会明确标出:
Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007f8b4c005a00 (object 0x000000071a201230, a java.lang.Object), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00007f8b4c005b00 (object 0x000000071a201240, a java.lang.Object), which is held by "Thread-1"
这个输出直接告诉你哪两个线程、哪两个对象在互相锁死——但注意,它只报告“已发生的死锁”,对“即将发生的”无能为力。所以核心还是编码阶段就约束锁顺序,而不是靠事后诊断。
最容易被忽略的一点:静态工具(如 SpotBugs)能检测部分锁顺序不一致模式,但对动态生成锁对象(比如基于账户ID新建的new Object())完全无效——这种死锁,只能靠设计契约和 Code Review 来守住底线。










