A deadlock occurs when two or more threads are blocked forever because they are waiting for each other to release resources. In other words, each thread holds a resource and waits for a resource held by another thread, creating a circular dependency.
How Deadlocks Happen
Deadlocks typically happen when:
- Multiple threads hold locks on resources.
- Threads acquire locks in different orders.
- A thread holds a lock and waits for another thread to release a lock, while the other thread is waiting for the first one to release a lock.
Deadlock: Deadlock occurs when two or more threads have a circular dependency on a pair of synchronized objects. For example, Thread 1 holds Lock A and waits for Lock B, while Thread 2 holds Lock B and waits for Lock A.
Example Scenario:
- Consider two resources Resource1 and Resource2 and two threads Thread1 and Thread2.
- Thread1 locks Resource1 and then tries to lock Resource2.
- Thread2 locks Resource2 and then tries to lock Resource1.
- If Thread1 locks Resource1 and waits for Resource2, and Thread2 locks Resource2 and waits for Resource1, a deadlock occurs.
- This scenario is demonstrated in following program.
//ThreadDeadLockDemo.java
class Resource {
private final Object lock = new Object();
public void method1(Resource other) {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": locked resource 1");
try { Thread.sleep(50); } catch (InterruptedException e) {}
other.method2();
}
}
public void method2() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": locked resource 2");
}
}
}
public class ThreadDeadLockDemo {
public static void main(String[] args) {
Resource resource1 = new Resource();
Resource resource2 = new Resource();
Thread thread1 = new Thread(() -> {
resource1.method1(resource2);
}, "Thread 1");
Thread thread2 = new Thread(() -> {
resource2.method1(resource1);
}, "Thread 2");
thread1.start();
thread2.start();
System.out.println("Press Ctrl+c to stop operation");
}
}
/*
C:\>javac ThreadDeadLockDemo.java
C:\>java ThreadDeadLockDemo
Press Ctrl+c to stop operation
Thread 2: locked resource 1
Thread 1: locked resource 1
*/Correct Solution for above program
// ThreadDeadLockSolution.java
class Resource {
private final Object lock = new Object();
public void method1(Resource other) {
Resource first = this;
Resource second = other;
// Enforce a strict lock order to avoid deadlocks
if (System.identityHashCode(first) > System.identityHashCode(second)) {
first = other;
second = this;
}
System.out.println(Thread.currentThread().getName() + ": Trying to acquire lock on resource 1");
synchronized (first.lock) {
System.out.println(Thread.currentThread().getName() + ": locked resource 1");
try { Thread.sleep(50); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + ": Trying to acquire lock on resource 2");
synchronized (second.lock) {
System.out.println(Thread.currentThread().getName() + ": locked resource 2");
other.method2();
}
System.out.println(Thread.currentThread().getName() + ": released lock on resource 2");
}
System.out.println(Thread.currentThread().getName() + ": released lock on resource 1");
}
public void method2() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": locked resource 2 (inside method2)");
System.out.println(Thread.currentThread().getName() + ": released lock on resource 2 (inside method2)");
}
}
}
public class ThreadDeadLockSolution {
public static void main(String[] args) {
Resource resource1 = new Resource();
Resource resource2 = new Resource();
Thread thread1 = new Thread(() -> {
resource1.method1(resource2);
}, "Thread 1");
Thread thread2 = new Thread(() -> {
resource2.method1(resource1);
}, "Thread 2");
System.out.println("Attempting to start threads...");
thread1.start();
thread2.start();
// Simulate Deadlock Detection Message (In real cases, it may need a watchdog timer)
try {
Thread.sleep(100);
System.out.println("Potential deadlock situation detected!");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Deadlock avoided due to lock ordering.");
System.out.println("Press Ctrl+C to stop operation.");
}
}
/*
C:\>javac ThreadDeadLockSolution.java
C:\>java ThreadDeadLockSolution
Attempting to start threads...
Thread 1: Trying to acquire lock on resource 1
Thread 2: Trying to acquire lock on resource 1
Thread 1: locked resource 1
Thread 1: Trying to acquire lock on resource 2
Thread 1: locked resource 2
Thread 1: locked resource 2 (inside method2)
Thread 1: released lock on resource 2 (inside method2)
Thread 1: released lock on resource 2
Thread 1: released lock on resource 1
Thread 2: locked resource 1
Potential deadlock situation detected!
Thread 2: Trying to acquire lock on resource 2
Deadlock avoided due to lock ordering.
Press Ctrl+C to stop operation.
Thread 2: locked resource 2
Thread 2: locked resource 2 (inside method2)
Thread 2: released lock on resource 2 (inside method2)
Thread 2: released lock on resource 2
Thread 2: released lock on resource 1
*/Deadlocks can severely impact performance and cause threads to be stuck indefinitely. It’s crucial to design thread synchronization carefully, maintain a consistent lock order, and monitor for potential deadlocks to ensure smooth multi-threaded execution.
