IMPLEMENTATION QUALITY / OBJECT DESIGN BRIEF

Concurrency and thread safety

Thread safety means an object behaves correctly when accessed by multiple threads at once.

AdvancedPhase 07 / Topic 7 of 8ResponsibilitiesCollaborationsExtensibility
01

Overview

Thread safety means an object behaves correctly when accessed by multiple threads at once. Without it, race conditions occur: two threads read a counter, both increment, and one update is lost; two gates assign the same parking spot; two users book the same seat. Concurrency questions are a frequent part of LLD interviews for parking lots, booking systems, rate limiters, caches, and schedulers.

Tools include immutability (no shared mutable state), confinement (one thread owns the data), atomic variables (AtomicInteger, compare-and-set), locks (synchronized, ReentrantLock, read-write locks), concurrent collections (ConcurrentHashMap, BlockingQueue), and higher-level designs like single-writer queues and actors. The key skill is identifying check-then-act and read-modify-write sequences that must be atomic.

Two cashiers and one last concert ticket

Both cashiers check the system, see one ticket left, and sell it at the same moment. A lock is a rule that only one cashier can touch the ticket drawer at a time, so the second sees 'sold out'.

02

When to use it

  • Shared state accessed by multiple threads or requests.
  • Allocating limited resources (spots, seats, tokens).
  • Background workers and schedulers.
03

Where it shows up in interviews

Resource allocation

Recognize it when: multiple gates or users claim limited items.

  • Design a parking lot with multiple entrances
  • Design a movie ticket system
  • Design an elevator system
Shared counters and caches

Recognize it when: concurrent reads and writes.

  • Design a thread-safe LRU cache
  • Design a rate limiter
  • Design a task scheduler
04

Where it is used in real software

java.util.concurrent

ConcurrentHashMap, AtomicLong, ReentrantLock, and ExecutorService are the standard toolkit.

Database locking

SELECT ... FOR UPDATE and optimistic version checks serialize access across servers.

Node.js event loop

Single-threaded JavaScript avoids data races in memory but still faces races across async awaits and processes.

05

Key terms

Race condition
Outcome depends on thread timing.
Critical section
Code that must run exclusively.
Atomicity
Operation happens entirely or not at all, with no interleaving.
Visibility
Writes by one thread seen by others (volatile, happens-before).
Deadlock
Threads wait on each other's locks forever.
06

How it works, step by step

  1. 1
    Identify shared mutable state

    Fields accessed by multiple threads.

  2. 2
    Find compound actions

    check-then-act, read-modify-write.

  3. 3
    Choose a strategy

    Immutability, atomics, locks, concurrent collections, or confinement.

  4. 4
    Keep critical sections small

    No I/O inside locks.

  5. 5
    Avoid deadlocks

    Consistent lock ordering, timeouts; test with many threads.

07

Race on the last parking spot

Two gates call park() at the same moment; one spot left

Step 1 / 5
TimeGate AGate BResult
t1findFreeSpot() -> S7--
t2-findFreeSpot() -> S7-
t3assign(S7, car1)--
t4-assign(S7, car2)Two cars, one spot
FixAtomic claim (lock or compareAndSet)Second claim fails, tries next spotCorrect

NOWTime: t1 | Gate A: findFreeSpot() -> S7 | Gate B: - | Result: -

The check (find free spot) and act (assign) must be one atomic operation.

08

Implementation

public final class ParkingSpot {    private final String id;    private final AtomicReference<String> occupant = new AtomicReference<>();     public ParkingSpot(String id) { this.id = id; }     // Atomic claim: only one thread can move from null to a plate    public boolean tryOccupy(String plate) { return occupant.compareAndSet(null, plate); }    public void release() { occupant.set(null); }    public boolean isFree() { return occupant.get() == null; }    public String id() { return id; }} public final class Floor {    private final List<ParkingSpot> spots;    public Floor(List<ParkingSpot> spots) { this.spots = List.copyOf(spots); }     public Optional<ParkingSpot> park(String plate) {        for (ParkingSpot s : spots) {            if (s.isFree() && s.tryOccupy(plate)) return Optional.of(s); // retry next spot if lost race        }        return Optional.empty();    }} // Thread-safe counter per key without explicit locksConcurrentHashMap<String, LongAdder> hits = new ConcurrentHashMap<>();hits.computeIfAbsent("GET /orders", k -> new LongAdder()).increment();
09

Complexity and performance

CAS operationO(1), lock-free

May retry under contention.

Lock contentionSerializes threads

Keep critical sections tiny.

10

Trade-offs

Coarse vs fine-grained locks

One big lock is simple but limits parallelism; per-item locks scale but risk deadlocks.

Pessimistic vs optimistic

Locks block; optimistic CAS or version checks retry and suit low contention.

11

Variants and related techniques

Single-writer principle

One thread owns mutations; others send messages (actors, event loops).

Read-write locks

Many concurrent readers, exclusive writers.

Distributed locks

Across processes: database locks, Redis, etcd.

12

Common mistakes

  • Check-then-act without atomicity.

    Fix: Combine into one atomic operation (CAS, putIfAbsent, lock).

  • I/O inside synchronized blocks.

    Fix: Hold locks only for in-memory updates.

  • Inconsistent lock ordering.

    Fix: Always acquire locks in a global order to avoid deadlocks.

13

Interview questions

How do you prevent two gates from assigning the same spot?

Make the claim atomic: compareAndSet on the spot's occupant, a lock per floor or spot, or a single allocator thread consuming requests from a queue. The losing gate retries with the next free spot.

What is the difference between synchronized and AtomicInteger?

synchronized locks a block of code for mutual exclusion and visibility; AtomicInteger uses lock-free compare-and-set for single-variable updates, which is faster under low contention but cannot protect multi-variable invariants.

14

Practice problems

ProblemDifficultyWhat it trains
Thread-safe LRU cacheMediumLocks around linked map.
Concurrent seat booking with holdsHardAtomic claims and expiry.