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.