Answer
Deadlock in Java
Deadlock occurs when two or more threads are blocked forever, each waiting for a resource held by the other.
Deadlock Example
Java
public class DeadlockDemo {
private static final Object LOCK_A = new Object();
private static final Object LOCK_B = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (LOCK_A) {
System.out.println("T1: holding A, waiting for B");
try { Thread.sleep(100); } catch (Exception e) {}
synchronized (LOCK_B) {
System.out.println("T1: acquired B");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (LOCK_B) { // T2 acquires B
System.out.println("T2: holding B, waiting for A");
try { Thread.sleep(100); } catch (Exception e) {}
synchronized (LOCK_A) { // T2 waits for A — DEADLOCK!
System.out.println("T2: acquired A");
}
}
});
t1.start();
t2.start();
// T1 holds A waiting for B
// T2 holds B waiting for A → DEADLOCK
}
}
4 Conditions for Deadlock (Coffman Conditions)
- ✓Mutual Exclusion — one thread at a time can hold the lock
- ✓Hold and Wait — thread holds one lock while waiting for another
- ✓No Preemption — locks can't be forcibly taken
- ✓Circular Wait — T1 waits for T2, T2 waits for T1
Prevention Strategies
1. Lock Ordering — Always acquire locks in the same order
Java
// Both threads acquire A then B — no deadlock possible
Thread t1 = new Thread(() -> {
synchronized (LOCK_A) {
synchronized (LOCK_B) { // same order as T2
System.out.println("T1 done");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (LOCK_A) { // SAME order — A first, then B
synchronized (LOCK_B) {
System.out.println("T2 done");
}
}
});
2. tryLock with Timeout (java.util.concurrent.locks)
Java
import java.util.concurrent.locks.*;
import java.util.concurrent.TimeUnit;
ReentrantLock lockA = new ReentrantLock();
ReentrantLock lockB = new ReentrantLock();
Thread t1 = new Thread(() -> {
try {
if (lockA.tryLock(1, TimeUnit.SECONDS)) {
try {
if (lockB.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("T1 acquired both locks");
} finally { lockB.unlock(); }
} else {
System.out.println("T1: couldn''t get B — releasing A");
}
} finally { lockA.unlock(); }
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
3. Use Higher-Level Concurrency Utilities
Java
// Prefer ExecutorService over raw threads
ExecutorService executor = Executors.newFixedThreadPool(4);
// Prefer ConcurrentHashMap over synchronized HashMap
Map<String, String> map = new ConcurrentHashMap<>();
// Prefer BlockingQueue for producer-consumer
BlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
Detecting Deadlock — Thread Dump
Bash
# Get thread dump (find deadlocked threads)
kill -3 <pid> # Unix
Ctrl+Break # Windows console
jstack <pid> # JDK tool
In Automation (Parallel Testing)
Java
// Deadlock risk in parallel tests sharing WebDriver
// Fix: use ThreadLocal to give each thread its own driver
private static final ThreadLocal<WebDriver> driverPool = new ThreadLocal<>();
public static WebDriver getDriver() {
if (driverPool.get() == null) {
driverPool.set(new ChromeDriver());
}
return driverPool.get();
}
@AfterMethod
public void teardown() {
WebDriver driver = driverPool.get();
if (driver != null) {
driver.quit();
driverPool.remove(); // clean up — prevent memory leak
}
}
