Java Concurrency - Deadlock

Deadlock beschreibt eine Situation, in der zwei oder mehr Threads für immer blockiert sind und aufeinander warten. Deadlock tritt auf, wenn mehrere Threads dieselben Sperren benötigen, diese jedoch in unterschiedlicher Reihenfolge erhalten. Ein Java-Multithread-Programm kann unter der Deadlock-Bedingung leiden, weil diesynchronizedDas Schlüsselwort bewirkt, dass der ausführende Thread blockiert, während auf die dem angegebenen Objekt zugeordnete Sperre oder Überwachung gewartet wird. Hier ist ein Beispiel.

Beispiel

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...");
            }
         }
      }
   } 
}

Wenn Sie das obige Programm kompilieren und ausführen, stellen Sie eine Deadlock-Situation fest. Die folgende Ausgabe wird vom Programm erzeugt:

Ausgabe

Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

Das obige Programm bleibt für immer hängen, da keiner der Threads in Position ist, um fortzufahren und darauf zu warten, dass sich die Sperre aufhebt, sodass Sie das Programm verlassen können, indem Sie STRG + C drücken.

Beispiel für eine Deadlock-Lösung

Lassen Sie uns die Reihenfolge der Sperre ändern und dasselbe Programm ausführen, um festzustellen, ob beide Threads noch aufeinander warten.

Beispiel

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...");
            }
         }
      }
   } 
}

Das Ändern der Reihenfolge der Sperren verhindert also, dass das Programm in eine Deadlock-Situation gerät, und führt zu folgendem Ergebnis:

Ausgabe

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...

Das obige Beispiel soll nur das Konzept verdeutlichen. Es ist jedoch ein komplexes Konzept, und Sie sollten sich eingehend damit befassen, bevor Sie Ihre Anwendungen für Deadlock-Situationen entwickeln.