The Java Memory Model (JMM) Flashcards

KOTLIN › Concurrency

What is the Java Memory Model, in one sentence?
The rulebook that defines when one thread's writes to shared memory are guaranteed to become visible to another thread, given that threads may cache data and compilers/CPUs may reorder instructions.
Why can thread B simply never see a write thread A made, without any synchronisation?
B may be reading its own cached copy of the field and A's write may still sit in a store buffer or register. Unless a happens-before edge connects A's write to B's read, the JMM allows B to read the stale value forever.
Name the three problems that fall out of the JMM and their one-line fixes.
Visibility (stale cached reads: fix with volatile or a lock), atomicity (interleaved read-modify-write loses updates: fix with atomics or a lock), and ordering (reordered instructions publish half-built state: fix with volatile, synchronized, or final).
Why does volatile NOT fix count++, and what does?
count++ is three steps: read, add, write. Volatile makes each read/write visible but two threads can still both read the same old value and overwrite each other. You need the whole read-modify-write to be atomic: AtomicInteger (CAS) or a lock. Knowing this distinction is a classic senior signal.
What is the ordering problem, concretely?
The compiler/CPU may reorder independent stores, e.g. publish instance = ref before the constructor's field writes. Another thread then sees a non-null reference to a half-built object. volatile on the reference, a lock around access, or final fields forbid the harmful reorder.
Define happens-before precisely.
A relation over actions: if A happens-before B, then A's effects (writes) are visible to B and A is ordered before it. It includes program order within one thread, the synchronisation edges between threads, and is transitive (A hb B and B hb C gives A hb C).
List the canonical happens-before edges.
A volatile write happens-before every subsequent read of that field. Unlocking a monitor happens-before the next lock of the same monitor. Thread.start() happens-before everything in the started thread; everything in a thread happens-before join() on it returning.
What do final fields guarantee under the JMM?
If the object is safely constructed (this doesn't escape the constructor), every thread sees its final fields fully initialised, with no synchronisation at all. This is why immutable objects are inherently thread-safe and why final/val-heavy design removes whole classes of races.
How does the JMM explain 'just use ConcurrentHashMap' and Kotlin's tools?
Its internals (CAS, per-bin locks) create the happens-before edges for you, so a get() sees a completed put() without external sync; per-key compound ops (compute, merge) add atomicity. Kotlin maps the primitives directly: @Volatile, atomics, Mutex, and immutable val state.

Back to The Java Memory Model (JMM)