Careeroza
Deadlock
What is a Deadlock
A deadlock happens when two or more threads each hold a lock and wait for a lock held by the other. None can move, forever.
Thread 1: holds A ──── wants B
▲ │
│ ▼
Thread 2: wants A ──── holds B// Transfer from account a to b locks a then b.
// Thread 1: transfer(acc1, acc2) → locks acc1, waits for acc2
// Thread 2: transfer(acc2, acc1) → locks acc2, waits for acc1 → DEADLOCK
void transfer(Account from, Account to, int amount) {
synchronized (from) {
synchronized (to) {
from.debit(amount);
to.credit(amount);
}
}
}Four Conditions
A deadlock needs all four (Coffman conditions). Break any one to prevent it.
- Mutual exclusion: a lock is held by one thread at a time.
- Hold and wait: a thread holds one lock and waits for another.
- No preemption: a lock cannot be taken away.
- Circular wait: T1 waits for T2 which waits for T1. ← easiest to break with a global lock order.
Fix: Always Lock in the Same Order
Example
Locking the account with the smaller id first means two opposite transfers can never wait on each other.
public class Main {
public static void main(String[] args) throws InterruptedException {
Account a = new Account(1, 1000), b = new Account(2, 1000);
Thread t1 = new Thread(() -> { for (int i = 0; i < 10_000; i++) Bank.transfer(a, b, 1); });
Thread t2 = new Thread(() -> { for (int i = 0; i < 10_000; i++) Bank.transfer(b, a, 1); });
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println("No deadlock. a=" + a.balance + " b=" + b.balance + " total=" + (a.balance + b.balance));
}
}
class Account {
final int id; int balance;
Account(int id, int balance) { this.id = id; this.balance = balance; }
}
class Bank {
static void transfer(Account from, Account to, int amount) {
Account first = from.id < to.id ? from : to;
Account second = from.id < to.id ? to : from;
synchronized (first) {
synchronized (second) {
from.balance -= amount;
to.balance += amount;
}
}
}
}Output
No deadlock. a=1000 b=1000 total=2000
Finding Deadlocks
Tip: Run jstack <pid> (or take a thread dump from VisualVM / IntelliJ). The JVM prints Found one Java-level deadlock with the threads and locks involved. Other fixes: tryLock(timeout) from ReentrantLock, or fewer, coarser locks.