Concept

Race Conditions & Lost Updates

The core problem

A race condition occurs when the correctness of a result depends on the unpredictable interleaving of concurrent operations. The classic failure mode is the lost update: two clients read the same value, each computes a new value from the stale copy, and one write silently overwrites the other.

Read-modify-write is the danger zone

Consider an inventory counter at stock = 10. Two requests both want to decrement it:

  • Request A reads 10, computes 9.
  • Request B reads 10 (before A writes), computes 9.
  • A writes 9. B writes 9.

Two units were sold but stock only dropped by one — the update from one request was lost. The same pattern corrupts wallet balances, like counts, seat reservations, and any aggregate that is read, modified in application code, then written back.

Two families of solutions

You can either detect the conflict and retry (optimistic concurrency), or prevent the interleaving by serializing access (pessimistic locking). Atomic primitives such as a single-statement UPDATE ... SET stock = stock - 1 or a compare-and-swap sidestep the read-modify-write window entirely and should always be your first choice when the operation can be expressed atomically.

The window between one client's read and its write is exactly where another writer sneaks in and clobbers the result.

Lost Update — two writers, one survivesClient AClient BDB10read 10read 10write 99write 99Two decrements applied → final value should be 8, but it is 9

Both solution families close this window — one by detecting that the value changed, the other by blocking the second writer until the first is done.