Deadlock in Java Multithreading and Prevention Strategies
1. What is Deadlock?
A deadlock is a situation in Java multithreading where two or more threads are blocked forever,
waiting for each other to release a resource. This happens when multiple threads hold some shared
resources and wait indefinitely for other resources held by other threads.
Example of Deadlock Scenario
• Thread A locks Resource 1 and waits for Resource 2.
• Thread B locks Resource 2 and waits for Resource 1.
• Both threads wait indefinitely, causing a deadlock.
2. How Does Deadlock Occur?
Deadlock occurs when the following four conditions hold simultaneously:
1. Mutual Exclusion → A resource can only be accessed by one thread at a time.
2. Hold and Wait → A thread holds a resource and waits for another.
3. No Preemption → A resource cannot be forcibly taken away.
4. Circular Wait → A cycle of dependencies is created between threads.
3. Example of Deadlock in Java
class Resource {
void methodA(Resource otherResource) {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " locked " + this);
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (otherResource) {
System.out.println(Thread.currentThread().getName() + " locked " + otherResource);
public class DeadlockExample {
public static void main(String[] args) {
Resource resource1 = new Resource();
Resource resource2 = new Resource();
Thread thread1 = new Thread(() -> resource1.methodA(resource2), "Thread-1");
Thread thread2 = new Thread(() -> resource2.methodA(resource1), "Thread-2");
thread1.start();
thread2.start();
Output (Deadlock Situation)
Thread-1 locked Resource@1a2b3c
Thread-2 locked Resource@4d5e6f
(Threads are stuck waiting forever.)
4. How to Prevent Deadlock in Java?
1. Avoid Nested Locks (Use Lock Ordering)
Always acquire locks in a fixed, consistent order to prevent circular waiting.
Example (Corrected Code with Lock Ordering)
class SafeResource {
void methodA(SafeResource otherResource) {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " locked " + this);
synchronized (otherResource) { // Always lock in the same order
System.out.println(Thread.currentThread().getName() + " locked " + otherResource);
Ensures that Thread-1 and Thread-2 acquire locks in the same sequence, preventing circular
wait.
2. Use Try-Lock Instead of Synchronized (Avoid Waiting Forever)
Use tryLock() from ReentrantLock instead of synchronized, so threads do not wait indefinitely.
Example Using tryLock()
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ResourceSafe {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
void safeMethod() {
while (true) {
if (lock1.tryLock()) {
try {
if (lock2.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " acquired both locks");
break;
} finally { lock2.unlock(); }
} finally { lock1.unlock(); }
// Retry after some time
try { Thread.sleep(50); } catch (InterruptedException ignored) {}
public class TryLockExample {
public static void main(String[] args) {
ResourceSafe resource = new ResourceSafe();
Thread t1 = new Thread(resource::safeMethod, "Thread-1");
Thread t2 = new Thread(resource::safeMethod, "Thread-2");
t1.start();
t2.start();
If a thread cannot acquire both locks, it releases the first lock and retries, avoiding deadlock.
3. Use a Timeout to Avoid Infinite Waiting
If a thread cannot acquire a lock within a set time, it backs off and retries later.
Example Using tryLock(timeout)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
class TimeoutResource {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
void safeMethod() {
try {
if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
System.out.println(Thread.currentThread().getName() + " acquired both locks");
} finally { lock2.unlock(); }
} finally { lock1.unlock(); }
} else {
System.out.println(Thread.currentThread().getName() + " could not acquire locks,
retrying...");
} catch (InterruptedException ignored) {}
public class TimeoutExample {
public static void main(String[] args) {
TimeoutResource resource = new TimeoutResource();
Thread t1 = new Thread(resource::safeMethod, "Thread-1");
Thread t2 = new Thread(resource::safeMethod, "Thread-2");
t1.start();
t2.start();
If a thread cannot acquire both locks within 100ms, it retries later, preventing deadlock.
4. Use a Single Lock Instead of Multiple Locks
If possible, use one lock for all resources instead of multiple locks.
Example Using a Single Lock
import java.util.concurrent.locks.ReentrantLock;
class SingleLockResource {
private final ReentrantLock lock = new ReentrantLock();
void method() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " is executing.");
} finally {
lock.unlock();
public class SingleLockExample {
public static void main(String[] args) {
SingleLockResource resource = new SingleLockResource();
Thread t1 = new Thread(resource::method, "Thread-1");
Thread t2 = new Thread(resource::method, "Thread-2");
t1.start();
t2.start();
Since both threads use the same lock, deadlock cannot occur.
5. Summary of Deadlock Prevention Strategies
Strategy Description Effectiveness
Lock Ordering Always acquire locks in a fixed order Highly effective
Acquire locks only if available, avoid
Try-Lock (tryLock()) Prevents indefinite waiting
waiting
Timeout on Locks Use tryLock(timeout) to retry later Avoids long waits
Single Lock
Use one lock instead of multiple locks Prevents circular wait
Approach
Do not hold one lock while waiting for Reduces risk but not always
Avoid Nested Locks
another possible
6. Conclusion
• Deadlock is a critical issue in Java multithreading that occurs when threads wait indefinitely
for each other.
• Prevention strategies like lock ordering, tryLock, timeouts, and single locks help avoid
deadlocks.
• Choosing the right strategy depends on the application requirements.
Would you like a real-world example, such as preventing deadlocks in a banking transaction
system?