Initialization safety provides for an object to be seen by an external thread in its fully constructed (initialized) state. The prerequisite is that the object should not be published prematurely ie. in its constructor. Once this is ensured, JMM requires certain behavior for the fields that are declared as final
. First, all final
object fields are guaranteed to be seen by an external thread in its fully initialized state. This is not as trivial as it sounds.
Consider a class:
class A {
List list;
A() {
list = Arrays.asList(some init expressions that adds 10 elements to list);
}
}
A thread that accesses the list
of A's
instance is not by default guaranteed to see 10 elements in that list. In fact, this thread can even see list
as null
. However, if list
is declared final
, then, as required by JMM, the list
must always appear to be initialized with 10 elements in it.
Secondly, this initialization guarantee is not limited to the final
field itself but is extended recursively to all objects referred by it. For example, if the list
in the above example is a list of lists themselves, then the external thread is guaranteed to see the inner lists as fully initialized.
Note that nowhere are we using synchronized
to achieve this safety in memory visibility (happens-before relationship).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…