An abstract/snippet from Java Concurrency In Practice-
// Unsafe publication
public Holder holder;
public void initialize(){
holder = new holder(42);
}
Two things can go wrong with improperly published objects. Other threads could see a stale value for the holder field, and thus see a null reference or other older value even though a value has been placed in holder. But far worse, other threads could see an up-todate value for the holder reference, but stale values for the state of the Holder. To make things even less predictable, a thread may see a stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertSanity can throw AssertionError.
Also object reference becomes visible to another thread does not necessarily mean that the state of that object is visible to the consuming thread
public class Holder{
private int n;
public Holder(int n) {
this.n = n;
}
public void assertSanity(){
if (n != n)
throw new AssertionError("This statement is false.");
}
}
Ofcouse, one of the ways to fix it would be to do/ make
public volatile Holder holder;
The author suggests a different approach-
If Holder were immutable, assertSanity could not throw AssertionError, even if the Holder was not properly published.)
public class Holder{
private final int n;
//...
}
But how? The unsafe publication is still there. I think it is still possible for a thread to get a null reference on holder. Please suggest.
The jls describes the special semantics of final fields
https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5
final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. [...]. final fields must be used correctly to provide a guarantee of immutability.
But i suggest you read the whole chapter 17.5
"must be used correctly" refers to constructor has actually ended (and did not escaped this
) and no fiddling with reflection.
Translated from http://www.angelikalanger.com/Articles/EffectiveJava/38.JMM-Overview/38.JMM-Overview.html that is:
The end of the constructor causes a partial flush, writing all final variables and dependend objects into memory. [...]. The first reading access of a final variable causes a partial refresh, loading the final variables and depending objects from memory. Another refersh does not occur [...].