Multithreading
Deadlock
Understand deadlock conditions (Coffman conditions), prevention techniques, and thread dump analysis.
Interview: Commonly tested by asking you to write a deadlock scenario and then rewrite it to resolve the deadlock, or explain how to prevent it.
A deadlock is a state where two or more threads are blocked forever, each waiting for a lock held by the other. Preventing deadlocks requires understanding resource acquisition orders.
Core Idea
Deadlocks happen when threads acquire locks in conflicting orders (e.g. Thread 1 gets A then B, Thread 2 gets B then A).
Why It Matters
Deadlocks freeze applications completely. The only way to resolve a deadlock is to restart the application.
Interview Lens
Expect questions on Coffman conditions and how to prevent deadlocks using global lock ordering or tryLock timeouts.
The Four Coffman Conditions
All four conditions must hold simultaneously for a deadlock to occur:
- Mutual Exclusion: At least one resource must be held in a non-shareable mode (only one thread can hold it).
- Hold and Wait: A thread must hold at least one lock and be waiting for another lock held by another thread.
- No Preemption: Locks cannot be forcibly taken from a thread; they must be released voluntarily.
- Circular Wait: Thread 1 waits for a lock held by Thread 2, who waits for a lock held by Thread 3, who waits for a lock held by Thread 1.
Code Walkthrough
The following example demonstrates how a deadlock occurs and how ordering lock acquisition resolves it.
public class DeadlockDemo { private static final Object lock1 = new Object(); private static final Object lock2 = new Object();public static void main(String[] args) { // Deadlocked thread: locks lock1 then lock2 new Thread(() -> { synchronized (lock1) { try { Thread.sleep(50); } catch (InterruptedException e) {} synchronized (lock2) { System.out.println("Thread 1 acquired both locks"); } } }).start();
// Conflicting thread: locks lock2 then lock1 -> Deadlock! new Thread(() -> { synchronized (lock2) { try { Thread.sleep(50); } catch (InterruptedException e) {} synchronized (lock1) { System.out.println("Thread 2 acquired both locks"); } } }).start();
// FIX: Ensure both threads acquire locks in the exact same order: lock1 first, then lock2. } }
Interview-Relevant Information
Q: How do you identify a deadlock in a running JVM?
Answer: You can generate a thread dump using tools like jcmd <pid> Thread.dump_to_file, jstack, or by sending a SIGQUIT signal (Ctrl+\). The thread dump analyzer will scan the threads and display a dedicated section detailing any detected deadlocks, showing which threads are blocked waiting on which monitor addresses.
Quick Checklist
What are the four Coffman conditions? How do you prevent deadlocks? If yes, you understand how to write deadlock-free code.
Use Cases
Preventing database write deadlocks in concurrent transaction managers.
Designing multi-resource allocation systems (e.g. Dining Philosophers problem solutions).
Common Mistakes
Acquiring locks dynamically based on caller order, which causes random circular waits under concurrent loads.
Holding locks while waiting for external dependencies or I/O resources.