了解为什么在此实现中发生死锁

Sex*_*ast 8 java concurrency multithreading deadlock

我是多线程的新手,我遇到了这个例子:

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...");
            }
         }
      }
   } 
}
Run Code Online (Sandbox Code Playgroud)

这会导致以下示例输出:

Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...
Run Code Online (Sandbox Code Playgroud)

即,存在僵局.但是,如果我们改变在第二个线程中获得的锁的顺序,那么它现在看起来像这样:

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...");
            }
         }
      }
   } 
}
Run Code Online (Sandbox Code Playgroud)

它按预期工作,示例输出如下所示:

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...
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释第一个导致死锁的情况,以及为什么第二个代码的更改会修复它?

Mar*_*oun 5

这是第一种情况的可能情景:

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

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

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

只有在它完成执行后,它才会释放两个锁(因为它退出synchronized块),现在JVM可以自由决定选择哪个线程,但实际上并不重要,同样的逻辑也会发生.