What is a race condition? Show one and explain why it hap… — Cracked Java
// Concurrency & Multithreading · Synchronization & Intrinsic Locks
MidTheoryBig TechAmazonGoogle

What is a race condition? Show one and explain why it happens.

A race condition is when the correctness of a program depends on the relative timing or interleaving of threads — typically because a multi-step operation on shared state is not atomic, so two threads' steps overlap and one clobbers the other.

The classic example

count++ looks like one operation but is three: read count, add one, write count back. With no synchronization, two threads can read the same value, both increment it, and both write back the same result — losing an update.

class Counter {
    private int count = 0;
    public void increment() { count++; }   // read-modify-write, NOT atomic
    public int get() { return count; }
}

// Two threads each call increment() 1_000_000 times.
// Expected: 2_000_000. Actual: usually less.

The interleaving that loses an update:

Thread-A: read count (5)
Thread-B: read count (5)
Thread-A: 5 + 1 = 6, write 6
Thread-B: 5 + 1 = 6, write 6   <-- A's increment vanished
Lost update on count++

Two flavors

This is a read-modify-write race. The other common kind is check-then-act: lazy init, if (instance == null) instance = new X();, or if (!map.containsKey(k)) map.put(k, v) — the gap between the check and the act lets another thread invalidate the check.

Why it happens

Two independent reasons, both rooted in the Java Memory Model:

  1. Atomicity — the compound operation can be interrupted mid-way by another thread.
  2. Visibility — without a happens-before edge, a write by one thread may never become visible to another; each may work off a stale, cached value.

Fixing it

Establish mutual exclusion and a happens-before edge:

public synchronized void increment() { count++; }

Or use a lock-free atomic, which is usually faster under contention:

private final AtomicInteger count = new AtomicInteger();
public void increment() { count.incrementAndGet(); }

Note that volatile alone does not fix this — it gives visibility but not atomicity, and count++ is still a non-atomic compound action.

Mark your status