Concurrencia de Java: punto muerto

Deadlock describe una situación en la que dos o más subprocesos se bloquean para siempre, esperando el uno al otro. El interbloqueo ocurre cuando varios subprocesos necesitan los mismos bloqueos pero los obtienen en un orden diferente. Un programa Java multiproceso puede sufrir la condición de interbloqueo porque elsynchronizedLa palabra clave hace que el subproceso en ejecución se bloquee mientras espera el bloqueo o monitor asociado con el objeto especificado. Aquí hay un ejemplo.

Ejemplo

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

Cuando compila y ejecuta el programa anterior, encuentra una situación de interbloqueo y la siguiente es la salida producida por el programa:

Salida

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

El programa anterior se bloqueará para siempre porque ninguno de los hilos está en posición de continuar y esperando que el otro libere el bloqueo, por lo que puede salir del programa presionando CTRL + C.

Ejemplo de solución de interbloqueo

Cambiemos el orden del bloqueo y ejecutemos el mismo programa para ver si ambos hilos aún se esperan el uno al otro -

Ejemplo

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

Entonces, simplemente cambiar el orden de los bloqueos evita que el programa entre en una situación de punto muerto y se completa con el siguiente resultado:

Salida

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

El ejemplo anterior es solo para aclarar el concepto, sin embargo, es un concepto complejo y debe profundizar en él antes de desarrollar sus aplicaciones para lidiar con situaciones de punto muerto.