我是多线程的新手,我遇到了以下示例:

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();

   public static void main(String args[]) {

      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }

   private static class ThreadDemo1 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class ThreadDemo2 extends Thread {
      public void run() {
         synchronized (Lock2) {
            System.out.println("Thread 2: Holding lock 2...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            synchronized (Lock1) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   }
}

这将导致以下示例输出:
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

即存在僵局。但是,如果我们更改在第二个线程中获得的锁的顺序,以便现在看起来像这样:
public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();

   public static void main(String args[]) {

      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }

   private static class ThreadDemo1 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class ThreadDemo2 extends Thread {
      public void run() {
         synchronized (Lock1) {
            System.out.println("Thread 2: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 2...");
            synchronized (Lock2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   }
}

它可以按预期工作,并且示例输出如下所示:
Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...

有人可以向我解释导致死锁的第一个事件是什么,为什么第二个代码的更改可以解决该问题?

最佳答案

这是第一种情况的可能方案:

线程1获取Lock1并进入睡眠状态10毫秒。现在,线程2获取Lock2并进入睡眠状态10毫秒。

现在,线程1尝试获取Lock2,但由于它是由线程2获取的,所以无法获取它,而线程2试图获取被线程1锁定的Lock1

在第二种情况下,我们假设选择第一个线程来运行。它获取Lock1,而另一个线程被阻止,因为它也尝试获取Lock1。现在线程1进入睡眠状态,并进入第二个(嵌套的)同步块。它尝试获取它(因为它仍然是免费的)-现在他获得了 2个锁。另一个线程仍然被阻止。

仅在完成执行后,它才释放两个锁(因为它退出了同步块),现在JVM可以自由决定选择哪个线程了,但这并不重要,发生相同的逻辑。

07-27 23:17