Each thread can cache values and the compiler can reorder instructions, so a write in one thread is not guaranteed to be seen by another without a synchronization action. The Java Memory Model defines those guarantees.
The visibility problem
Without synchronization, a background thread may loop forever on a stale copy of
running because it never re-reads main memory.
private volatile boolean running = true;
public void stop() { running = false; }
public void run() {
while (running) {
process();
}
}Happens-before is the contract
volatile writes, lock releases, and thread starts all establish
happens-before edges that make prior writes visible to later reads.
// write, then read on another thread — volatile guarantees visibility
config = loaded; // plain write
ready = true; // volatile write publishes config safelyTakeaways
volatileguarantees visibility and ordering, but not atomicity of compound ops.- Use
synchronizedorjava.util.concurrenttypes for read-modify-write. - Reason in terms of happens-before, not intuition about timing.
For counters and flags that need atomic updates, reach for AtomicInteger or
AtomicReference rather than volatile alone.