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

全部评论

相关推荐

09-18 20:41
百度_Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务