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

ConcurrencyBackend engineeringInterview preparation

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

Practise in a real repository

Explaining a concept and enforcing it in code are different skills, and machine coding rounds test the second. Gronex ships broken backend repositories whose test suites assert the invariant rather than the happy path.

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.

Related

More backend concepts