Simple Lock Ordering DeadLock Example

Let us consider an example program that deadlocks, and then see how we could have avoided that. Below example is an example for a lock ordering deadlock.

The DeadLockExample class has two objects lockObject1 and lockObject2, which we will use as locks for synchronizing.

We will have two Runnables, which we will use for creating two threads: Runnable1 synchronizes on lockObject1 and try to get lockObject2, and Runnable2 synchronizes on lockObject2 and try to get lockObject1.

Sometimes, due to some lucky timing this might not go into deadlock, for example, if Runnable1 gets lockObject1 and also gets lockObject2 before Runnable2. Therefore for our demo, we will use a Thread.sleep() after acquiring first lock.

Remember that, Thread.sleep() call does not release the lock, but keeps the lock while sleeping, unlike the wait method that will release the lock and wait. 

 

Program

public class DeadLockExample {

  final static Object lockObject1= new Object();

  final static Object lockObject2= new Object();

 

  public static void main(String[] args) {

Thread t1 = new Thread(new Runnable1());

    t1.setName("Thread A");

    t1.start();

    Thread t2 = new Thread(new Runnable2());

    t2.setName("Thread B");

    t2.start();

  }

 

}

 

class Runnable1 implements Runnable

{

public void run()

  {

synchronized (DeadLockExample.lockObject1)

    {

      System.out.println(Thread.currentThread().getName()+": Got lockObject1. Trying for lockObject2");

      try {

        Thread.sleep(500);

        //DeadLockExample.lockObject1.wait(500);

      //DeadLockExample.lockObject1.wait();

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

synchronized (DeadLockExample.lockObject2)

      {

        System.out.println(Thread.currentThread().getName()+": Got lockObject2.");

      }

    }

  }

}

 

class Runnable2 implements Runnable

{

public void run()

  {

synchronized (DeadLockExample.lockObject2)

    {

      System.out.println(Thread.currentThread().getName()+": Got lockObject2. Trying for lockObject1");

      try {

        Thread.sleep(500);

        //DeadLockExample.lockObject2.wait(500);

      //DeadLockExample.lockObject2.wait();

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

synchronized (DeadLockExample.lockObject1)

      {

        System.out.println(Thread.currentThread().getName()+": Got lockObject1.");

//DeadLockExample.lockObject1.notify();

      }

    }

  }

}

 

The output will be:

Thread A: Got lockObject1. Trying for lockObject2

Thread B: Got lockObject2. Trying for lockObject1

 

Even though a program has the potential to deadlock, it may never deadlock at all, and will only happen with some bad timings. So we have used Thread.sleep() to simulate that bad timing, so that we can demonstrate deadlock.

 

Avoiding Deadlock

Thread.sleep() will hold the lock while sleeping whereas, wait() method will release the lock and wait. 

So replace Thread.sleep(500); with DeadLockExample.lockObject1.wait(500). The statement wait(500) will release the lock and wait for 500 milli seconds or until someone notifies it using a notify or notifyall method.

When you call wait, you are actually releasing your lock and hence other thread can acquire it and will then release it.

After 500 milliseconds, Thread 1 will again be runnable and acquire the released lock. So there won't be any deadlock.

 

Now, replace DeadLockExample.lockObject1.wait(500) with DeadLockExample.lockObject1.wait(). The program will hang again as noone is notifying the wait method to wake up. However this is not a deadlock. This is because the hold and wait condition of deadlock is not met here. You can confirm this by looking into the thread dump.

 

Getting Thread Dumps

You can use jconsole, jvisualvm or jps to get the process id of your program and then run jstack <process-id> to get the thread stack dump. 

You can use the same commands for a program running from an eclipse also.

References and notes: 

Java Concurrency in Practice by Brian Goetz, David Holmes, DOug Lea, Tim Peierls, Joshua Bloch and Joseph Bowbeer. 

http://javajee.com/deadlock-in-operating-systems

Quick Notes Finder Tags

Activities (1) advanced java (1) agile (3) App Servers (6) archived notes (2) Arrays (1) Best Practices (12) Best Practices (Design) (3) Best Practices (Java) (7) Best Practices (Java EE) (1) BigData (3) Chars & Encodings (6) coding problems (2) Collections (15) contests (3) Core Java (All) (55) course plan (2) Database (12) Design patterns (8) dev tools (3) downloads (2) eclipse (9) Essentials (1) examples (14) Exception (1) Exceptions (4) Exercise (1) exercises (6) Getting Started (18) Groovy (2) hadoop (4) hibernate (77) hibernate interview questions (6) History (1) Hot book (5) http monitoring (2) Inheritance (4) intellij (1) java 8 notes (4) Java 9 (1) Java Concepts (7) Java Core (9) java ee exercises (1) java ee interview questions (2) Java Elements (16) Java Environment (1) Java Features (4) java interview points (4) java interview questions (4) javajee initiatives (1) javajee thoughts (3) Java Performance (6) Java Programmer 1 (11) Java Programmer 2 (7) Javascript Frameworks (1) Java SE Professional (1) JPA 1 - Module (6) JPA 1 - Modules (1) JSP (1) Legacy Java (1) linked list (3) maven (1) Multithreading (16) NFR (1) No SQL (1) Object Oriented (9) OCPJP (4) OCPWCD (1) OOAD (3) Operators (4) Overloading (2) Overriding (2) Overviews (1) policies (1) programming (1) Quartz Scheduler (1) Quizzes (17) RabbitMQ (1) references (2) restful web service (3) Searching (1) security (10) Servlets (8) Servlets and JSP (31) Site Usage Guidelines (1) Sorting (1) source code management (1) spring (4) spring boot (3) Spring Examples (1) Spring Features (1) spring jpa (1) Stack (1) Streams & IO (3) Strings (11) SW Developer Tools (2) testing (1) troubleshooting (1) user interface (1) vxml (8) web services (1) Web Technologies (1) Web Technology Books (1) youtube (1)