How can two threads with interleaved writes/reads print [0, 0]?
Two threads each write one field and then read the other. Explain how [0, 0] is possible without @Volatile, what @Volatile rules out, and what is still not guaranteed.
class State { var x = 0; var y = 0 }
// t1: state.x = 1; println(state.y)
// t2: state.y = 1; println(state.x)
Diagnose the cause of the [0, 0] output.
Each thread's write may not be visible to the other, and reordering lets both reads run before either write lands — so [0, 0] is legal. @Volatile on x and y adds happens-before edges that exclude [0, 0], but [1, 1] still needs synchronization or a join.
- ✗Assuming program-order writes are always visible to other threads instantly
- ✗Thinking
@Volatileguarantees the[1, 1]result, not just excluding[0, 0] - ✗Believing single writes need atomicity rather than visibility/ordering here
- →Why does
@Volatileexclude[0, 0]but not force[1, 1]? - →How would a
joinbefore the reads guarantee[1, 1]?
The behaviour
Without memory barriers the Java Memory Model (JMM) permits:
- Write invisibility — t1's write
x = 1may not yet be visible to t2. - Reordering — the compiler/CPU may reorder an independent write and read.
class State { var x = 0; var y = 0 }
// t1: state.x = 1; println(state.y) // may read y = 0
// t2: state.y = 1; println(state.x) // may read x = 0
So all four outcomes are possible, including [0, 0]: both reads run before the other's write becomes visible.
The narrowing
Mark x and y @Volatile. That establishes happens-before: a read that sees the start cannot miss a prior write — [0, 0] is excluded.
class State { @Volatile var x = 0; @Volatile var y = 0 }
But [1, 1] is still not guaranteed — it depends on timing. To force exactly [1, 1] you need explicit synchronization (e.g. join the threads before reading, or a shared barrier).