18.3.6 死锁产生条件与预防措施
1. 死锁基础概念
1.1 什么是死锁
public class DeadlockBasics {
/*
* 死锁定义:
* 两个或多个线程永久阻塞,每个线程都在等待其他线程释放资源
*/
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void demonstrateDeadlock() {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("线程1获得锁1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("线程1等待锁2...");
synchronized (lock2) {
System.out.println("线程1获得锁2");
}
}
}, "Thread-1");
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("线程2获得锁2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("线程2等待锁1...");
synchronized (lock1) {
System.out.println("线程2获得锁1");
}
}
}, "Thread-2");
thread1.start();
thread2.start();
// 检查死锁
try {
Thread.sleep(5000);
if (thread1.isAlive() || thread2.isAlive()) {
System.out.println("检测到死锁!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
1.2 死锁的四个必要条件
public class DeadlockConditions {
/*
* 死锁的四个必要条件(Coffman条件):
*
* 1. 互斥条件:资源不能被多个线程同时使用
* 2. 占有和等待条件:线程持有资源同时等待其他资源
* 3. 不可剥夺条件:资源不能被强制抢占
* 4. 循环等待条件:存在线程等待环路
*/
public void demonstrateConditions() {
demonstrateMutualExclusion();
demonstrateHoldAndWait();
demonstrateCircularWait();
}
private void demonstrateMutualExclusion() {
System.out.println("--- 互斥条件演示 ---");
final Object exclusiveResource = new Object();
Runnable task = () -> {
synchronized (exclusiveResource) {
System.out.println(Thread.currentThread().getName() + "获得互斥资源");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
};
new Thread(task, "互斥线程1").start();
new Thread(task, "互斥线程2").start();
}
private void demonstrateHoldAndWait() {
System.out.println("--- 占有和等待条件演示 ---");
final Object resource1 = new Object();
final Object resource2 = new Object();
Thread holdAndWaitThread = new Thread(() -> {
synchronized (resource1) {
System.out.println("线程持有资源1,等待资源2");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
synchronized (resource2) {
System.out.println("线程获得资源2");
}
}
});
holdAndWaitThread.start();
}
private void demonstrateCircularWait() {
System.out.println("--- 循环等待条件演示 ---");
final Object resourceA = new Object();
final Object resourceB = new Object();
// 线程1: A -> B
Thread thread1 = new Thread(() -> {
synchronized (resourceA) {
System.out.println("线程1持有A,等待B");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (resourceB) {
System.out.println("线程1获得B");
}
}
});
// 线程2: B -> A (形成循环)
Thread thread2 = new Thread(() -> {
synchronized (resourceB) {
System.out.println("线程2持有B,等待A");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (resourceA) {
System.out.println("线程2获得A");
}
}
});
thread1.start();
thread2.start();
}
}
2. 死锁检测与诊断
2.1 使用ThreadMXBean检测死锁
public class DeadlockDetection {
public void detectDeadlock() {
// 创建死锁场景
createDeadlockScenario();
// 使用ThreadMXBean检测
detectUsingThreadMXBean();
}
private void createDeadlockScenario() {
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("线程1完成");
}
}
}, "DeadlockThread-1");
Thread t2 = new Thread(() -> {
synchronized (lock2) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("线程2完成");
}
}
}, "DeadlockThread-2");
t1.start();
t2.start();
}
private void detectUsingThreadMXBean() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null) {
System.out.println("检测到死锁!涉及线程数: " + deadlockedThreads.length);
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(deadlockedThreads);
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("死锁线程: " + threadInfo.getThreadName());
System.out.println("线程状态: " + threadInfo.getThreadState());
System.out.println("阻塞信息: " + threadInfo.getLockInfo());
}
scheduler.shutdown();
}
}, 1, 2, TimeUnit.SECONDS);
// 10秒后停止检测
try {
Thread.sleep(10000);
if (!scheduler.isShutdown()) {
scheduler.shutdown();
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
查看13道真题和解析