Volatile: visibility, not atomicity
What volatile guarantees, the lost-increment race, safe publication, and final-field semantics.
volatile gives you exactly two things โ and not a third:
- Visibility: every read sees the latest write (hb edge per access).
- Ordering: the compiler/CPU may not reorder volatile accesses with each other in observable ways.
What volatile does NOT give: atomicity of compound actions.
volatile int n; n++ is still a read-modify-write race โ two threads can
both read 5 and both write 6, losing an increment. That is what
AtomicInteger (CAS) is for โ next module.
Safe publication (ยง17.4.4): to hand an object to another thread safely,
publish it through a channel that carries an hb edge โ a volatile field, a
BlockingQueue, an executor submit, or a properly synchronized structure.
If you construct an object and store it in a plain static field, another
thread may see a partially constructed object (fields default-valued or
stale).
Final-field semantics (ยง17.5): if an object is properly constructed
(no this escape), every thread that gets a reference to it sees the final
fields fully initialized โ even without synchronization. This guarantee is
why String is safe to share freely, and why leaking this from a
constructor is not just ugly but a correctness bug: it can break the
final-field guarantee.