✅ 一、常见死锁示例代码(经典双锁互持)
public class DeadlockDemo {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
synchronized (lock1) {
System.out.println("线程A:获得 lock1,等待 lock2...");
try {
Thread.sleep(100); // 模拟业务处理时间
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("线程A:获得 lock2");
}
}
});
Thread threadB = new Thread(() -> {
synchronized (lock2) {
System.out.println("线程B:获得 lock2,等待 lock1...");
try {
Thread.sleep(100); // 模拟业务处理时间
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("线程B:获得 lock1");
}
}
});
threadA.start();
threadB.start();
}
}
🧨 死锁触发条件说明:
-
线程A先获得
lock1,等待lock2 -
线程B先获得
lock2,等待lock1 -
二者互相等待,进入死锁状态
✅ 二、如何定位死锁?(详细工具与命令)
🧪 现象
-
程序无响应/线程卡住
-
接口调用无响应、日志长时间无输出
-
CPU占用不高,但线程数不变,且阻塞线程增加
🛠 步骤一:定位 Java 进程
jps -l
# 输出:12345 DeadlockDemo
🛠 步骤二:使用 jstack 打印线程栈
jstack 12345
🛠 步骤三:查找关键死锁提示
输出内容中查找关键词:
Found one Java-level deadlock:
"Thread-0": waiting to lock monitor 0x000..., which is held by "Thread-1"
"Thread-1": waiting to lock monitor 0x000..., which is held by "Thread-0"
🔍 你可以看到:
-
哪些线程处于死锁
-
哪个锁(monitor)被哪个线程持有
-
哪个线程在等待哪个锁
🧠 补充命令说明:
| 命令 | 说明 |
|---|---|
jps -l | 列出当前运行的 Java 进程 |
jstack <pid> | 打印线程堆栈,检测死锁 |
kill -3 <pid> | 打印线程信息到控制台(Linux) |
jconsole / jvisualvm | 图形界面查看死锁与线程状态 |
✅ 三、怎么解决死锁?
🧭 原则:避免循环等待条件发生
✅ 常用解决方案:
1. 统一加锁顺序
所有线程都按
lock1 -> lock2的顺序加锁,避免交叉等待。
2. 使用 tryLock() 加超时控制
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
try {
if (lock2.tryLock(1, TimeUnit.SECONDS)) {
try {
// 正常执行逻辑
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
3. 减少锁粒度 / 合并资源
如果多个资源锁可以合并为一个整体锁,降低并发复杂性
4. 死锁监控与告警机制
-
定期 dump 线程
-
对超时任务自动分析堆栈
-
Prometheus + AlertManager 配置线程阻塞告警
✅ 四、面试中如何回答(参考答法)
我遇到过死锁问题,通常是由于多个线程竞争多个资源,且锁获取顺序不一致造成的。在排查时,我会先通过
jps获取 Java 进程号,然后使用jstack打印线程栈。死锁信息会明确指出哪些线程互相等待。我们常用的解决方式包括统一加锁顺序、使用ReentrantLock的tryLock配合超时机制,以及在高并发系统中通过监控系统预警线程阻塞情况。在项目中,也建立了定期线程 dump 的自动化脚本以便复现问题。
✅ 五、总结:死锁排查命令清单
| 步骤 | 命令 | 说明 |
|---|---|---|
| 1 | jps -l | 获取进程号 |
| 2 | jstack <pid> | 查看线程状态 |
| 3 | kill -3 <pid> | 输出线程信息(Linux) |
| 4 | jconsole/jvisualvm | 图形化工具辅助分析 |
| 5 | grep 关键词分析 | 查找 deadlock、BLOCKED、WAITING 等状态 |

701

被折叠的 条评论
为什么被折叠?



