Concurrency
Happens-before relationship: interview questions and how to answer them
Happens-before is the memory-model relation that guarantees visibility and ordering between actions across threads; wall-clock order alone does not.
Written and reviewed by Sahil Srivastav
What it actually is
If action A happens-before action B, the effects of A are visible to B and the permitted execution cannot reorder B before A in a way that changes the guarantee. It is a partial order, not a timestamp and not a claim that A physically finished earlier on a CPU.
Locks, volatile writes and reads, thread start and join, and successful publication through concurrent collections create happens-before edges. Two ordinary writes to shared memory have no such edge merely because one appears first in source code.
Why it matters in production
Without a happens-before edge, a worker can loop forever on a cached flag, observe fields in an impossible order, or read stale configuration. These are correctness failures even when no data race is visible in a local test.
The relation lets you reason locally: identify the write, identify the synchronisation edge, and identify the read. If no edge connects them, the code has no visibility guarantee.
How it works
Program order
Actions in one thread are ordered before later actions in that thread, but that order reaches another thread only through synchronisation.
Release and acquire
A release such as a volatile write or unlock publishes prior writes; a matching acquire such as a volatile read or lock gives the reader those writes.
Transitivity
If A happens-before B and B happens-before C, A happens-before C. This is how a producer can publish through a queue to a consumer.
Data-race freedom
A conflicting access without a happens-before edge is a data race. Atomicity of one field does not make a compound invariant safe.
Implementing it
Draw the edges around shared state rather than adding sleeps. Use locks or concurrent collections as the publication boundary.
Keep immutable state behind one safely published reference and avoid exposing partially built objects.
Use race detectors, stress tests, and the language memory model to validate the design; a passing test at one timing proves little.
Interview questions and how to answer them
What does happens-before guarantee?
Visibility and ordering: every write before the edge is visible to the read after it, subject to the language memory model.
Does volatile make `count++` safe?
No. Each read and write is visible, but the increment is a read-modify-write that can lose updates. Use an atomic increment or a lock.
How does a queue publish work?
The enqueue operation’s release synchronises with the dequeue’s acquire, so the consumer sees the item’s fully constructed state.
Why is sleep not a fix?
It changes timing without establishing a memory-order edge. The bug remains legal and reappears under different scheduling.
Answers that lose the round
- Treating source order as inter-thread order
- Using sleep as synchronisation
- Assuming atomic increments protect multiple fields
- Publishing a mutable object before construction completes
- Forgetting join or task completion as a visibility edge
- Confusing visibility with mutual exclusion
FAQ
Is happens-before the same as happens-before in logs?
No. Log timestamps show observations; happens-before is a formal memory-model guarantee.
Does a lock provide visibility if it is never contended?
Yes. The unlock and subsequent lock form the edge regardless of whether a thread had to wait.
Can immutable state remove all memory barriers?
No. It reduces mutation, but initial publication still needs a defined edge.