A detailed example of Java's deadlock resolution method

  • 2020-07-21 07:50:41
  • OfStack

A deadlock is a situation in which multiple threads are blocked simultaneously, with one or all of them waiting for a resource to be released. Because the thread is blocked indefinitely, the program cannot terminate normally.

Four requirements for java deadlocks:

1 > Mutex: when a resource is used (occupied) by one thread, other threads cannot use it

2 > Non-preemption, the resource requester cannot forcibly take the resource from the resource occupant, the resource can only be released by the resource occupant.

3 > Request and hold, that is, when the resource requester requests other resources while maintaining the original resources comrade.

4 > Cyclic waiting, that is, there is a waiting queue: P1 holds the resources of P2, P2 the resources of P3, and P3 the resources of P1. This creates a waiting loop.

When all four conditions are true, a deadlock is formed. Of course, in the case of a deadlock, breaking any of the above conditions will make the deadlock disappear. The java code is used to simulate 1 deadlock generation.

The deadlock problem is solved by using synchronized and Lock explicitly.

However, if locks are used improperly and multiple objects are to be locked at the same time, a deadlock situation can occur, as follows:


/*
 author by w3cschool.cc
 LockTest.java
 */
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  Start to perform ");
     while(true){
      synchronized (LockTest.obj1) {
        System.out.println(new Date().toString() + " LockA  Lock the  obj1");
        Thread.sleep(3000); //  Here wait is given B It locks up opportunities 
        synchronized (LockTest.obj2) {
         System.out.println(new Date().toString() + " LockA  Lock the  obj2");
         Thread.sleep(60 * 1000); //  For testing, hold on to it 
        }
      }
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
  }
}
class LockB implements Runnable{
  public void run() {
   try {
     System.out.println(new Date().toString() + " LockB  Start to perform ");
     while(true){
      synchronized (LockTest.obj2) {
        System.out.println(new Date().toString() + " LockB  Lock the  obj2");
        Thread.sleep(3000); //  Here wait is given A It locks up opportunities 
        synchronized (LockTest.obj1) {
         System.out.println(new Date().toString() + " LockB  Lock the  obj1");
         Thread.sleep(60 * 1000); //  For testing, hold on to it 
        }
      }
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
  }
}

The output result of the above code operation is:


Tue May 05 10:51:06 CST 2015 LockB  Start to perform 
Tue May 05 10:51:06 CST 2015 LockA  Start to perform 
Tue May 05 10:51:06 CST 2015 LockB  Lock the  obj2
Tue May 05 10:51:06 CST 2015 LockA  Lock the  obj1

This is where the deadlock occurs.

To solve this problem, we don't use display unlocking, we use semaphore control.

The semaphore controls how many threads the resource can be accessed by. Here we specify that it can only be accessed by one thread, which is similar to locking. The semaphore can specify the timeout to fetch, and we can do an extra processing based on that timeout.

In the case of unsuccessful attempts, it is generally a matter of repeating the attempt, or specifying the number of attempts, or exiting immediately.

Consider the following code:


/*
 author by w3cschool.cc
 UnLockTest.java
 */
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  Start to perform ");
     while (true) {
      if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
        System.out.println(new Date().toString() + " LockA  Lock the  obj1");
        if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
         System.out.println(new Date().toString() + " LockA  Lock the  obj2");
         Thread.sleep(60 * 1000); // do something
        }else{
         System.out.println(new Date().toString() + "LockA  The lock  obj2  failure ");
        }
      }else{
        System.out.println(new Date().toString() + "LockA  The lock  obj1  failure ");
      }
      UnLockTest.a1.release(); //  The release of 
      UnLockTest.a2.release();
      Thread.sleep(1000); //  Try it now, in the real world do something It's uncertain 
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
  }
}
class LockBb implements Runnable {
  public void run() {
   try {
     System.out.println(new Date().toString() + " LockB  Start to perform ");
     while (true) {
      if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
        System.out.println(new Date().toString() + " LockB  Lock the  obj2");
        if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
         System.out.println(new Date().toString() + " LockB  Lock the  obj1");
         Thread.sleep(60 * 1000); // do something
        }else{
         System.out.println(new Date().toString() + "LockB  The lock  obj1  failure ");
        }
      }else{
        System.out.println(new Date().toString() + "LockB  The lock  obj2  failure ");
      }
      UnLockTest.a1.release(); //  The release of 
      UnLockTest.a2.release();
      Thread.sleep(10 * 1000); //  This is just for demonstration purposes, so tryAcquire only 1 Second, and B Want to give A Allow time to execute, otherwise the two are always deadlocks 
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
  }
}

The output structure of the above example code is:


Tue May 05 10:59:13 CST 2015 LockA  Start to perform 
Tue May 05 10:59:13 CST 2015 LockB  Start to perform 
Tue May 05 10:59:13 CST 2015 LockB  Lock the  obj2
Tue May 05 10:59:13 CST 2015 LockA  Lock the  obj1
Tue May 05 10:59:14 CST 2015LockB  The lock  obj1  failure 
Tue May 05 10:59:14 CST 2015LockA  The lock  obj2  failure 
Tue May 05 10:59:15 CST 2015 LockA  Lock the  obj1
Tue May 05 10:59:15 CST 2015 LockA  Lock the  obj2

I hope this article has helped you


Related articles: