Safe publication is about memory visibility. The concept of memory visibility is a bit trickier than other thread safety issues such as race conditions.
Memory visibility issues arise when actions performed by one thread in certain order appear to be performed in different order for another thread (it may be caused by optimizations made by compiler or CPU).
In your case:
// Thread A
h = new Holder(42);
// Thread B
h.assertSanity();
For Thread A, n
is certainly initialized before h
.
But in absense of safe publication it's not guaranteed to be the same for Thread B. Thread B may see h
in initialized state, but n
won't be initialzed yet. Moreover, the state of n
as observed by Thread B may change during evaluation of n != n
, causing assertSanity()
to throw an exception.
Note that this problem is not something that is guaranteed to happen in all cases. You will probably never see this happening, but Java Memory Model doesn't guarantee correctness in this case nonetheless.