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圣经