死锁迷局:从预防到破解
文章目录
第一章 十字路口的僵局:认识死锁
1.1 交通堵塞的启示
想象早高峰的十字路口:
- 北向南的卡车(线程A)占据右侧车道(资源1)
- 西向东的轿车(线程B)占据左侧车道(资源2)
- 双方都在等待对方让出道路,结果整个路口瘫痪
这正是计算机世界中死锁的典型场景。去年双十一期间,某电商平台就因优惠券系统的死锁,导致3分钟内损失上千万订单。
1.2 死锁的四大必要条件
就像交通事故的认定标准:
条件 | 现实类比 | 技术解释 |
---|---|---|
互斥访问 | 单行车道每次只允许一辆车 | 资源不能共享 |
持有并等待 | 司机紧握方向盘不愿让行 | 已持有资源且等待新资源 |
不可抢占 | 不能强行拖走已停车辆 | 资源只能自愿释放 |
循环等待 | 四辆车各堵一个方向 | 等待链形成闭环 |
// 经典死锁代码示例
public class RoadDeadlock {
static final Object roadA = new Object();
static final Object roadB = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (roadA) {
System.out.println("卡车占领A道路");
try {
Thread.sleep(100); }
catch (InterruptedException e) {
}
synchronized (roadB) {
// 等待B道路
System.out.println("卡车通过路口");
}
}
}).start();
new Thread(() -> {
synchronized (roadB) {
System.out.println("轿车占领B道路");
synchronized (roadA) {
// 等待A道路
System.out.println("轿车通过路口");
}
}
}).start();
}
}
运行这段代码,你会看到程序永远卡住——这就是死锁的直观表现。
第二章 死锁诊断:化身系统法医
2.1 现场取证工具
当线上系统出现死锁,就像交警处理事故现场:
jstack诊断流程:
- 使用
top -Hp <pid>
找到卡死的Java进程 - 执行
jstack <pid> > thread_dump.txt
- 搜索输出中的
deadlock
关键词
示例诊断报告:
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007fe2bc007c58 (object 0x000000076b58d7c8, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007fe2bc006b88 (object 0x000000076b58d7d8, a java.lang.Object),
which is held by "Thread-1"
2.2 动态监测技术
Java提供的ThreadMXBean就像路口摄像头:
public class DeadlockDetector {
public static void main(String[] args) throws Exception {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
for (ThreadInfo info : infos) {
System.out.println("死锁线程:" + info.getThreadName());
System.out.println("等待资源:" + info.getLockName());
}
}
}
}
第三章 预防死锁的五大策略
3.1 资源排序法
就像给城市道路编号:
// 定义全局资源顺序
public class ResourceOrder {
public static final Object RESOURCE_1 = new Object();
public static final Object RESOURCE_2 = new