How Deadlock Occurs And How To Fix It In Java

Deadlock in Java

Deadlock describes a situation where two or more threads are blocked forever, waiting for each other. Java deadlock situation arises with at least two threads(multitasking or multi-threading) and two or more resources.

There are several ways you can detect deadlock in Java applications.

The following points may give you ideas how to detect deadlock in application code:

  • look for nested synchronized blocks
  • check if are calling a synchronized method from another
  • if you are trying to lock different object

Another way to find out deadlock using thread dump. To take thread dump in Linux system you can execute command kill -3. In Windows system you can do so by pressing Ctrl + Break from the command line tool. This will print status of all threads and you can check which thread is locked on which object.

Another option is to use jConsole/VisualVM, which comes with JDK. The jconsole.exe is found under the bin folder of JDK installation. You just need to double click on it. Connect to the Local Process in New Connection window and click on Connect button.

This is just an example and for actual application you have to find out your actual program to check the deadlock.

java deadlock fix

If you prompt for the insecure connection then click on Insecure connection to connect to the process.

java deadlock fix

Next you will find few tabs and click on the Threads tab to check the lock on the thread objects.

java deadlock fix

How Deadlock Occurs

Now let’s see how deadlock occurs in the program. This is the simple example and in an actual application there may be complex scenario where deadlock occurs.

Class Thread1

The following class extends Thread class and acquires locks on Person class followed by the Address class.

public class Thread1 extends Thread {

	@Override
	public void run() {
		synchronized (Person.class) {
			System.out.println("Thread1: Holding lock on Person");

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			System.out.println("Thread1: Waiting for lock on Address");

			synchronized (Address.class) {
				System.out.println("Thread1: Holding lock on Person and Address");
			}
		}
	}

}

Class Thread2

The Thread2 class extends Thread class and acquires locks on Address class followed by the Person class.

public class Thread2 extends Thread {

	@Override
	public void run() {
		synchronized (Address.class) {
			System.out.println("Thread2: Holding lock on Address");

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			System.out.println("Thread2: Waiting for lock on Person");

			synchronized (Person.class) {
				System.out.println("Thread2: Holding lock on Address and Person");
			}
		}
	}

}

Starting Threads

The following class creates new Thread instances and starts thread objects.

public class ThreadApp {

	public static void main(String[] args) {
		Thread1 thread1 = new Thread1();
		Thread2 thread2 = new Thread2();

		thread1.start();
		thread2.start();
	}

}

The above class produces the below output:

Thread2: Holding lock on Address
Thread1: Holding lock on Person
Thread2: Waiting for lock on Person
Thread1: Waiting for lock on Address

If run() methods in Thread1 and Thread2 classes is called by two or many threads, then there is a good chance of occurring deadlock situation, because if thread1 acquires lock on Person object while executing run() method and if thread2 acquires lock on Address object while running run() method, both threads will be waiting for each other to release lock on Person and Address objects to proceed further and it will never happen.

Deadlock Identification in Jconsole

Now you can check deadlock occurrence in jConsole/VisualVM:

deadlock fix in java

Now click on Threads tab once connected and click on Detect Deadlock or Deadlock tab on the bottom.

Clicking on each thread (Thread-0 or Thread-1), you will see the following output:

Thread-0

fix deadlock in java

Thread-1

deadlock in java

Resolving Deadlock in Java

Now you will see how to avoid deadlock or how to resolve the deadlock situation.

If you look at the above code minutely, then you may figure out that the real reason for the deadlock is not two or more threads are requesting resources or lock but the way they are requesting a lock creates deadlock situation. Therefore if you provide ordered access then the problem will be resolved.

Update the run() method in the Thread2 class as follows:

@Override
public void run() {
	synchronized (Person.class) {
		System.out.println("Thread2: Holding lock on Address");

		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("Thread2: Waiting for lock on Person");

		synchronized (Address.class) {
			System.out.println("Thread2: Holding lock on Address and Person");
		}
	}
}

Now when you run again the main class you will see the following output:

Thread2: Holding lock on Address
Thread2: Waiting for lock on Person
Thread2: Holding lock on Address and Person
Thread1: Holding lock on Person
Thread1: Waiting for lock on Address
Thread1: Holding lock on Person and Address

Now there is no deadlock because both run() methods in Thread1 and Thread2 are accessing lock on Address and Person classes in the same order. So, if thread1 acquires a lock on Address object, thread2 does not proceed until thread1 releases lock on Person object, in the same way thread1 will not be blocked even if thread2 holds lock on Person object, because now thread2 does not expect thread1 to release lock on Address object to proceed further.

Deadlock is the most common problem which arises with a little bit of carelessness during multi-threading programming and it can completely stop the program.

Source Code

Download

Leave a Reply

Your email address will not be published.