Java Program to Implement Deadlock Example
synchronized blocks on two objects in different order in two threads to create deadlock.Examples
How to Think About It
Algorithm
Code
public class DeadlockExample { private static final Object resource1 = new Object(); private static final Object resource2 = new Object(); public static void main(String[] args) { Thread thread1 = new Thread(() -> { synchronized (resource1) { System.out.println("Thread-1: Locked Resource 1"); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (resource2) { System.out.println("Thread-1: Locked Resource 2"); } } }); Thread thread2 = new Thread(() -> { synchronized (resource2) { System.out.println("Thread-2: Locked Resource 2"); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (resource1) { System.out.println("Thread-2: Locked Resource 1"); } } }); thread1.start(); thread2.start(); } }
Dry Run
Let's trace the deadlock example through the code with actual thread actions.
Thread-1 locks resource1
Thread-1 enters synchronized block on resource1 and prints "Thread-1: Locked Resource 1".
Thread-2 locks resource2
Thread-2 enters synchronized block on resource2 and prints "Thread-2: Locked Resource 2".
Thread-1 tries to lock resource2
Thread-1 waits because resource2 is locked by Thread-2.
Thread-2 tries to lock resource1
Thread-2 waits because resource1 is locked by Thread-1.
Deadlock occurs
Both threads wait forever for each other to release locks, causing deadlock.
| Thread | Locked Resource | Waiting For |
|---|---|---|
| Thread-1 | resource1 | resource2 |
| Thread-2 | resource2 | resource1 |
Why This Works
Step 1: Two resources locked in opposite order
Each thread locks one resource first, then tries to lock the other resource that the other thread holds, creating a circular wait.
Step 2: Synchronized blocks enforce exclusive access
The synchronized keyword ensures only one thread can hold the lock on a resource at a time.
Step 3: Sleep increases chance of deadlock
The Thread.sleep(100) pauses the thread to let the other thread lock its resource, making deadlock more likely.
Step 4: Both threads wait forever
Because each thread waits for the other to release a lock, neither can proceed, causing the program to hang.
Alternative Approaches
public class NoDeadlockExample { private static final Object resource1 = new Object(); private static final Object resource2 = new Object(); public static void main(String[] args) { Thread thread1 = new Thread(() -> { synchronized (resource1) { System.out.println("Thread-1: Locked Resource 1"); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (resource2) { System.out.println("Thread-1: Locked Resource 2"); } } }); Thread thread2 = new Thread(() -> { synchronized (resource1) { System.out.println("Thread-2: Locked Resource 1"); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } synchronized (resource2) { System.out.println("Thread-2: Locked Resource 2"); } } }); thread1.start(); thread2.start(); } }
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.TimeUnit; public class TryLockDeadlock { private static final Lock lock1 = new ReentrantLock(); private static final Lock lock2 = new ReentrantLock(); public static void main(String[] args) { Thread t1 = new Thread(() -> { try { if(lock1.tryLock(500, TimeUnit.MILLISECONDS)) { System.out.println("Thread-1: Locked lock1"); Thread.sleep(100); if(lock2.tryLock(500, TimeUnit.MILLISECONDS)) { System.out.println("Thread-1: Locked lock2"); lock2.unlock(); } lock1.unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); Thread t2 = new Thread(() -> { try { if(lock2.tryLock(500, TimeUnit.MILLISECONDS)) { System.out.println("Thread-2: Locked lock2"); Thread.sleep(100); if(lock1.tryLock(500, TimeUnit.MILLISECONDS)) { System.out.println("Thread-2: Locked lock1"); lock1.unlock(); } lock2.unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); t1.start(); t2.start(); } }
Complexity: O(1) time, O(1) space
Time Complexity
The deadlock example runs in constant time as it only involves locking two resources without loops.
Space Complexity
Only two resource objects and two threads are used, so space is constant.
Which Approach is Fastest?
The basic synchronized approach is simple but can deadlock; tryLock avoids deadlock but adds overhead.
| Approach | Time | Space | Best For |
|---|---|---|---|
| Synchronized blocks (deadlock) | O(1) | O(1) | Demonstrating deadlock |
| Synchronized blocks (same order) | O(1) | O(1) | Safe locking without deadlock |
| tryLock with timeout | O(1) | O(1) | Avoiding deadlock with retries |