Easy Tutorial
❮ Java Hashmap Data_Linklist ❯

Java Example - Deadlock and Solution

Java Examples

Deadlock is a situation where multiple threads are blocked, with one or all of them waiting for a resource to be released. Since the threads are blocked indefinitely, the program cannot terminate normally.

The four necessary conditions for a Java deadlock to occur are:

When all four conditions are met, a deadlock occurs. However, breaking any of these conditions can resolve the deadlock. Below is a Java code example to simulate deadlock.

The methods to solve the deadlock problem are: one is using synchronized, and the other is using Lock to explicitly lock.

Improper use of locks, especially when locking multiple objects simultaneously, can lead to deadlock, as shown below:

LockTest.java File

import java.util.Date;

public class LockTest {
   public static String obj1 = "obj1";
   public static String obj2 = "obj2";
   public static void main(String[] args) {
      LockA la = new LockA();
      new Thread(la).start();
      LockB lb = new LockB();
      new Thread(lb).start();
   }
}
class LockA implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockA 开始执行");
         while(true){
            synchronized (LockTest.obj1) {
               System.out.println(new Date().toString() + " LockA 锁住 obj1");
               Thread.sleep(3000); // This wait gives B a chance to lock
               synchronized (LockTest.obj2) {
                  System.out.println(new Date().toString() + " LockA 锁住 obj2");
                  Thread.sleep(60 * 1000); // For testing purposes, holding the lock
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class LockB implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockB 开始执行");
         while(true){
            synchronized (LockTest.obj2) {
               System.out.println(new Date().toString() + " LockB 锁住 obj2");
               Thread.sleep(3000); // This wait gives A a chance to lock
               synchronized (LockTest.obj1) {
                  System.out.println(new Date().toString() + " LockB 锁住 obj1");
                  Thread.sleep(60 * 1000); // For testing purposes, holding the lock
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

The output of the code above is:

Tue May 05 10:51:06 CST 2015 LockB started execution
Tue May 05 10:51:06 CST 2015 LockA started execution
Tue May 05 10:51:06 CST 2015 LockB locked obj2
Tue May 05 10:51:06 CST 2015 LockA locked obj1

At this point, a deadlock occurs.

To solve this problem, we avoid explicit unlocking and use semaphores to control access.

Semaphores can control how many threads can access a resource; here, we specify that only one thread can access, achieving a lock-like effect. Semaphores can also specify a timeout for acquiring access, allowing for additional handling based on this timeout.

For unsuccessful acquisition attempts, one typically retries or specifies a number of attempts before exiting immediately.

Here is the code:

UnLockTest.java file

import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class UnLockTest {
   public static String obj1 = "obj1";
   public static final Semaphore a1 = new Semaphore(1);
   public static String obj2 = "obj2";
   public static final Semaphore a2 = new Semaphore(1);

   public static void main(String[] args) {
      LockAa la = new LockAa();
      new Thread(la).start();
      LockBb lb = new LockBb();
      new Thread(lb).start();
   }
}
class LockAa implements Runnable {
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockA started execution");
         while (true) {
            if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
               System.out.println(new Date().toString() + " LockA locked obj1");
               if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
                  System.out.println(new Date().toString() + " LockA locked obj2");
                  Thread.sleep(60 * 1000); // do something
               } else {
                  System.out.println(new Date().toString() + " LockA failed to lock obj2");
               }
            } else {
               System.out.println(new Date().toString() + " LockA failed to lock obj1");
            }
            UnLockTest.a1.release(); // release
            UnLockTest.a2.release();
            Thread.sleep(1000); // immediately retry, in real scenarios the action is uncertain
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class LockBb implements Runnable {
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockB started execution");
         while (true) {
if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
   System.out.println(new Date().toString() + " LockB has locked obj2");
   if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
      System.out.println(new Date().toString() + " LockB has locked obj1");
      Thread.sleep(60 * 1000); // do something
   } else {
      System.out.println(new Date().toString() + " LockB failed to lock obj1");
   }
} else {
   System.out.println(new Date().toString() + " LockB failed to lock obj2");
}
UnLockTest.a1.release(); // release
UnLockTest.a2.release();
Thread.sleep(10 * 1000); // This is just for demonstration, so tryAcquire is set to 1 second, and B gives A a chance to execute, otherwise it would always be deadlock
}
} catch (Exception e) {
   e.printStackTrace();
}
}
}

The example code outputs:

Tue May 05 10:59:13 CST 2015 LockA starts executing
Tue May 05 10:59:13 CST 2015 LockB starts executing
Tue May 05 10:59:13 CST 2015 LockB has locked obj2
Tue May 05 10:59:13 CST 2015 LockA has locked obj1
Tue May 05 10:59:14 CST 2015 LockB failed to lock obj1
Tue May 05 10:59:14 CST 2015 LockA failed to lock obj2
Tue May 05 10:59:15 CST 2015 LockA has locked obj1
Tue May 05 10:59:15 CST 2015 LockA has locked obj2

Java Examples ```

❮ Java Hashmap Data_Linklist ❯