Consider the following code:
public class Resource {
public int val;
public Resource() {
val = 3;
}
}
public class UnsafePublication {
public static Resource resource;
public static void initialize() {
resource = new Resource();
}
}
In Thread1
UnsafePublication.initialize();
In Thread2
while (true) {
if (UnsafePublication.resource != null) {
System.out.println(UnsafePublication.resource.val);
break;
}
}
We know that the unsafe publication may lead to Thread2 printing 0 instead of 3.
After going through many reference materials, I concluded two explanations:
- Assume the assignment
resource = new Resource();
does write through, so Thread2 will findUnsafePublication.resource
is not null. But the assignmentval = 3;
in the constructor of Resource does not write through, so theval
will be the default 0 value. There is a reorder when assigning
new Resource()
toresource
. To be more specific:- allocate the memory for a Resource object
- call Resource' s constructor to initialize the object
- assign the object to the field "resource"
is reordered to:
- allocate the memory for a Resource object
- assign the object to the field "resource"
- call Resource' s constructor to initialize the object.
So if Thread1 just finishes the step2 in the reordered version, and Thread2 is swapped in, then Thread2 will find
UnsafePublication.resource.val
is the default 0 value.
So here is my question: Are both of the explanations correct and possible? And in the real world, are these two factors may even mixed to make the situation more complicated?