文章目录
- 多线程基础系列-线程死锁
-
- [1. 什么是线程死锁?](#1. 什么是线程死锁?)
- [2. 如何检测线程死锁?](#2. 如何检测线程死锁?)
- [3. 如何预防和避免线程死锁?](#3. 如何预防和避免线程死锁?)
多线程基础系列-线程死锁
1. 什么是线程死锁?
- 定义:两个或多个线程互相持有对方需要的资源并永久等待,导致线程都无法继续执行。
- 必要条件(同时满足才会发生):
- 互斥:资源一次只能被一个线程占用。
- 请求并保持:持有资源的同时再请求新资源。
- 不可剥夺:已获得的资源不能被强制抢占。
- 循环等待:形成资源等待环路。
- 一个经典示例:线程 A 持有锁 L1 等待 L2;线程 B 持有锁 L2 等待 L1,循环等待 → 死锁。

示例代码(故意制造死锁):
java
public class DeadlockDemo {
private static final Object L1 = new Object();
private static final Object L2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (L1) {
System.out.println("T1 get L1");
sleep(100);
System.out.println("T1 waiting get L2");
synchronized (L2) {
System.out.println("T1 acquired L1 and L2");
}
}
}, "T1");
Thread t2 = new Thread(() -> {
synchronized (L2) {
System.out.println("T2 get L2");
sleep(100);
System.out.println("T2 waiting get L1");
synchronized (L1) {
System.out.println("T2 acquired L2 and L1");
}
}
}, "T2");
t1.start();
t2.start();
}
private static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException ignored) {}
}
}
2. 如何检测线程死锁?
- 线程 Dump(推荐首选)
jstack <pid>:直接输出线程栈,底部会有 "Found one Java-level deadlock"。jcmd <pid> Thread.print:与 jstack 类似,可多次采样比对。jmap -histo:结合对象分布,辅助判断锁竞争热点。
- 可视化工具
- JConsole / VisualVM:线程页签可直接标红死锁线程。
这里以 JConsole 工具为例进行演示。
- 第一步运行我们编写的死锁示例

- 第二步我们要找到 JDK 的 bin 目录,找到 jconsole 并双击打开,并选择我死锁demo的进程

- 第三步:[线程]一栏点击"检测死锁"

- 最后就可以看到死锁线程的相关说明

3. 如何预防和避免线程死锁?
- 统一加锁顺序
- 约定所有线程获取多把锁的顺序,避免循环等待(如总是先锁 L1 再锁 L2)。

- 约定所有线程获取多把锁的顺序,避免循环等待(如总是先锁 L1 再锁 L2)。
- 减少锁粒度与持有时间
- 缩小同步块范围;避免在持锁期间执行 IO/远程调用。
- 尽量避免嵌套锁
- 能拆开的锁拆开;必要时将逻辑重构为无嵌套的步骤。
- 使用可中断/可超时锁
ReentrantLock.tryLock(timeout, unit):拿不到锁及时放弃,避免永久等待。
java
ReentrantLock lockA = new ReentrantLock();
if (lockA.tryLock(200, TimeUnit.MILLISECONDS)) {
try {
// 临界区
} finally {
lockA.unlock();
}
} else {
// 降级或重试逻辑
}
- 使用更高层并发工具
java.util.concurrent中的ConcurrentHashMap、BlockingQueue、Semaphore、StampedLock等,减少显式锁。
- 不可变与无共享设计
- 尽量使用不可变对象或线程封闭(Thread confinement),减少共享状态。
- 分离职责与锁分段
- 按领域拆分锁(lock striping),避免大锁串行化。
- 定期监控与压测
- 在预生产或压测环境跑热点场景,定期采集线程 Dump 进行巡检。