NOTE
6.37 Deadlock Example
A minimal Java deadlock caused by inconsistent lock ordering, plus detection and prevention techniques.
This is a historical learning note and may contain outdated or incomplete understanding.
1. Minimal Example
Two threads can deadlock when each holds one lock and waits for the other:
static final Object LOCK1 = new Object();
static final Object LOCK2 = new Object();
Thread a = new Thread(() -> {
synchronized (LOCK1) {
synchronized (LOCK2) {
// work
}
}
});
Thread b = new Thread(() -> {
synchronized (LOCK2) {
synchronized (LOCK1) {
// work
}
}
});
If a owns LOCK1 while b owns LOCK2, both can wait forever for the other monitor.
2. Why It Happens
The classic Coffman conditions are mutual exclusion, hold-and-wait, no forced preemption, and circular wait. Removing at least one necessary condition prevents this form of deadlock.
3. Diagnose It
A Java thread dump can show threads waiting for monitors and often reports a detected Java-level deadlock. Useful tools include jstack, jcmd Thread.print, and observability tooling that captures thread dumps.
4. Prevent It
The simplest rule for multiple locks is a global lock ordering: all code acquires the same locks in the same order.
Other approaches include reducing nested locking, using higher-level concurrent structures, or using timed tryLock with a deliberate retry/rollback policy when Lock is appropriate.