Memra

Deadlock, livelock & safe design strategies

Named hazards and the two strategies that eliminate most concurrency bugs before they start.

The classic hazards

Deadlock: thread A holds lock 1 and waits for lock 2; thread B holds lock 2 and waits for lock 1. Both block forever.

// Thread A:  synchronized(lock1) { synchronized(lock2) { … } }
// Thread B:  synchronized(lock2) { synchronized(lock1) { … } }
// — classic deadlock — both threads wait forever

The standard fix: always acquire locks in the same order across all threads. If thread A and thread B both take lock1 first, then lock2, only one can win lock1 — the other waits safely.

Livelock: threads keep responding to each other but neither makes progress — like two people in a corridor stepping aside simultaneously in the same direction, forever.

Starvation: a low-priority thread never gets CPU time because higher-priority threads monopolise it.

Two strategies that prevent most bugs

1. Immutability — if shared objects cannot be mutated, no synchronisation is needed:

// String, Integer, LocalDate, BigDecimal, all records — safe to share
final String config = "read-only";  // no lock ever needed

2. Thread confinement — each object belongs to exactly one thread; never shared:

// ThreadLocal gives each thread its own instance
ThreadLocal<SimpleDateFormat> fmt = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
fmt.get().format(new Date());  // safe — each thread has its own SDF

For new code, reach first for immutable types (records, List.of, Map.of, BigDecimal, java.time types) and confine mutable state to a single thread. Reach for synchronized or AtomicInteger only when state genuinely must cross thread boundaries.

Choosing the right tool:

| Need | Tool | |---|---| | Simple counter | AtomicInteger | | Guard a block of statements | synchronized | | Shared map | ConcurrentHashMap | | Producer/consumer | BlockingQueue | | Chain async operations | CompletableFuture | | Avoid sharing entirely | immutability / ThreadLocal |

NORMAL ~/memra/learn/java-from-zero/concurrency-hazards utf-8 LF