编写一个示例程序,展示如何产生多线程死锁的情况。

示例:多线程死锁

public class DeadlockExample {
    private static final Object resource1 = new Object(); // 资源 1
    private static final Object resource2 = new Object(); // 资源 2

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: Locked resource 1");

                try {
                    // 模拟某些操作
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Thread 1: Waiting to lock resource 2");
                synchronized (resource2) {
                    System.out.println("Thread 1: Locked resource 2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: Locked resource 2");

                try {
                    // 模拟某些操作
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Thread 2: Waiting to lock resource 1");
                synchronized (resource1) {
                    System.out.println("Thread 2: Locked resource 1");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

程序输出示例:

Thread 1: Locked resource 1
Thread 2: Locked resource 2
Thread 1: Waiting to lock resource 2
Thread 2: Waiting to lock resource 1

程序会卡在两个线程都等待对方释放锁的地方,形成死锁


程序详解:

  1. 死锁的产生原因
    • 线程 1 持有 resource1 的锁,尝试获取 resource2 的锁。
    • 线程 2 持有 resource2 的锁,尝试获取 resource1 的锁。
    • 两个线程相互等待对方释放资源,导致死锁。
  2. 模拟死锁
    • 使用 Thread.sleep(100) 模拟资源占用时间,增加死锁发生的可能性。
    • 线程 1 和线程 2 的锁定顺序不同(一个先锁定 resource1 再锁定 resource2,另一个相反),形成竞争条件。

如何避免死锁?

  1. 始终按相同顺序获取锁: 确保所有线程都以固定顺序请求锁,可以避免循环等待。

    修改代码:

    public class DeadlockAvoidance {
       private static final Object resource1 = new Object();
       private static final Object resource2 = new Object();
    
       public static void main(String[] args) {
           Thread thread1 = new Thread(() -> {
               synchronized (resource1) {
                   System.out.println("Thread 1: Locked resource 1");
                   synchronized (resource2) {
                       System.out.println("Thread 1: Locked resource 2");
                   }
               }
           });
    
           Thread thread2 = new Thread(() -> {
               synchronized (resource1) { // 修改为与线程 1 相同的锁顺序
                   System.out.println("Thread 2: Locked resource 1");
                   synchronized (resource2) {
                       System.out.println("Thread 2: Locked resource 2");
                   }
               }
           });
    
           thread1.start();
           thread2.start();
       }
    }
    
  2. 使用 tryLock()(ReentrantLock): 使用 java.util.concurrent.locks.ReentrantLock,尝试获取锁,避免死锁。

    示例:

    Lock lock1 = new ReentrantLock();
    Lock lock2 = new ReentrantLock();
    
    if (lock1.tryLock()) {
       try {
           if (lock2.tryLock()) {
               try {
                   // 执行任务
               } finally {
                   lock2.unlock();
               }
           }
       } finally {
           lock1.unlock();
       }
    }
    
  3. 检测和处理死锁: 使用线程监控工具(如 JConsole 或 VisualVM)检测和分析死锁。

发表评论

后才能评论