I am currently reading Java Concurrency in Practice by Brian Goetz. On page 51. In one of the footnotes, he stated:
While it may seem that field values set in a constructor are the first values written to those fields and therefore that there are no “older” values to see as stale values, the Object constructor first writes the default values to all fields before subclass constructors run. It is therefore possible to see the default value for a field as a stale value.
So, the concept of final fields is not clear to me now. Consider the sample class:
public class MyClass{
private final MyImmutableClass mic;
public MyClass(){
mic = MyImmutableClass.empty();
}
}
According to the above footnote, the mic
field is assigned twice, once by the Object
's constructor and once by the MyClass
's constructor itself. Now, imagine that we published a MyClass
object unsafely (e.g. through a public
field):
public final MyClass mc;
Who guarantees that mc
is always observed by any thread in a consistent state? Why can't some thread accidentally observe the default value?
To my knowledge, the final
field itself only guarantees that the reference cannot be assigned after object construction. If we declared mc
volatile, that would be clear. Any thread reading the field should read it from the memory directly. It's prohibited to read it from cache.
UPD: The publication example:
public static void main(String[] args){
class MyRunnable implements Runnable(){
private SomeClass sc;
public MyRunnable(SomeClass sc){
this.sc = sc;
}
public void run(){
//do some with sc
}
}
SomeClass sc = getInitialized();
ExecutorService es = Executors.newFixedThreadPool(10);
MyRunnable mr = new MyRunnable(sc);
//submiting mr to es 10 times
es.awaitTemination();
es.shutdown();
}
private static SomeClass getInitialized(){
SomeClass sc = new SomeClass();
sc. initialize();
return sc;
}
public class SomeClass
public MyClass mc;
public void initialize(){
mc = new MyClass();
}
}
A SomeClass
instance is going to be published across multiple threads. Can some thread observe the default value of the mic
field?
mc
in your example is an instance variable. This means you must have a fully initialized instance of the class that contains mc
in order for any code that accesses mc
of some instance not to throw a NullPointerException
. Therefore mc
will definitely be initialized by the time it is accessed.