Understanding Deadlock in Java: Causes and Solutions in Multithreading

Learn about deadlock in Java, a common issue in multithreading where two or more threads are waiting for each other’s resources, causing a standstill. Explore how deadlock occurs and strategies to prevent it in Java applications.



Deadlock in Java

Deadlock in Java is a part of multithreading. Deadlock can occur when a thread is waiting for an object lock that is acquired by another thread, and the second thread is waiting for an object lock that is acquired by the first thread. Since both threads are waiting for each other to release the lock, the condition is called deadlock.

Example of Deadlock in Java

Here is an example demonstrating deadlock in Java.

FileName: TestDeadlockExample1.java

public class TestDeadlockExample1 {  
public static void main(String[] args) {  
    final String resource1 = "ratan jaiswal";  
    final String resource2 = "vimal jaiswal";  
    
    // t1 tries to lock resource1 then resource2  
    Thread t1 = new Thread() {  
    public void run() {  
        synchronized (resource1) {  
        System.out.println("Thread 1: locked resource 1");  
        try { Thread.sleep(100); } catch (Exception e) {}  
        synchronized (resource2) {  
            System.out.println("Thread 1: locked resource 2");  
        }  
        }  
    }  
    };  
    
    // t2 tries to lock resource2 then resource1  
    Thread t2 = new Thread() {  
    public void run() {  
        synchronized (resource2) {  
        System.out.println("Thread 2: locked resource 2");  
        try { Thread.sleep(100); } catch (Exception e) {}  
        synchronized (resource1) {  
            System.out.println("Thread 2: locked resource 1");  
        }  
        }  
    }  
    };  
    
    t1.start();  
    t2.start();  
}  
}  
    
Output

Thread 1: locked resource 1
Thread 2: locked resource 2
    

More Complicated Deadlocks

A deadlock may also include more than two threads. For example:

  • Thread 1 locks A, waits for B
  • Thread 2 locks B, waits for C
  • Thread 3 locks C, waits for D
  • Thread 4 locks D, waits for A

Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thread 4, and thread 4 waits for thread 1.

How to Avoid Deadlock?

To avoid deadlocks, we need to address the pattern of accessing resources. A common solution is to re-order the statements where the code is accessing shared resources.

Example of Solving Deadlock

Here is an example that resolves deadlock by re-ordering the resource access.

FileName: DeadlockSolved.java

public class DeadlockSolved {  
public static void main(String ar[]) {  
    DeadlockSolved test = new DeadlockSolved();  
    final resource1 a = test.new resource1();  
    final resource2 b = test.new resource2();  
    
    // Thread-1  
    Runnable b1 = new Runnable() {  
    public void run() {  
        synchronized (b) {  
        try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }  
        synchronized (a) {  
            System.out.println("In block 1");  
        }  
        }  
    }  
    };  
    
    // Thread-2  
    Runnable b2 = new Runnable() {  
    public void run() {  
        synchronized (b) {  
        synchronized (a) {  
            System.out.println("In block 2");  
        }  
        }  
    }  
    };  
    
    new Thread(b1).start();  
    new Thread(b2).start();  
}  
    
// resource1  
private class resource1 {  
    private int i = 10;  
    public int getI() { return i; }  
    public void setI(int i) { this.i = i; }  
}  
    
// resource2  
private class resource2 {  
    private int i = 20;  
    public int getI() { return i; }  
    public void setI(int i) { this.i = i; }  
}  
}  
    
Output

In block 1
In block 2
    

How to Avoid Deadlock in Java?

Deadlocks cannot be completely resolved, but we can avoid them by following some basic rules:

  • Avoid Nested Locks: Avoid giving locks to multiple threads to prevent deadlock conditions.
  • Avoid Unnecessary Locks: Only give locks to important threads to avoid deadlock conditions.
  • Using Thread Join: A deadlock usually happens when one thread is waiting for the other to finish. Using join with a maximum time can help avoid this.