Reputation: 11279
At this tutorial (link) on Java's volatile declaration is this example:
public class BackgroundFloobleLoader {
public volatile Flooble theFlooble;
public void initInBackground() {
// do lots of stuff
theFlooble = new Flooble(); // this is the only write to theFlooble
}
}
public class SomeOtherClass {
public void doWork() {
while (true) {
// do some stuff...
// use the Flooble, but only if it is ready
if (floobleLoader.theFlooble != null)
doSomething(floobleLoader.theFlooble);
}
}
}
It is said that the background thread is loading from a database so I think the author means the instantiation new Flooble()
takes a significant amount of time.
To quote: Without the theFlooble reference being volatile, the code in doWork() would be at risk for seeing a partially constructed Flooble as it dereferences the theFlooble reference.
How can it be? I would have expected the opposite. That is, I would have expected that without the volatile declaration the thread invoking doWork
method would be at risk of seeing the Flooble belatedly or never at all.
Upvotes: 3
Views: 260
Reputation: 934
Compiler can inline Flooble's constructor and change order of initialization of its fields and assigning reference to theFlooble variable
I've seen this declared in blogs, SO posts, and numerous other places, but it directly contradicts the java language spec:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5
That in essence states, barring any exceptions, the constructor will complete before a reference is returned. If you don't have a reference before the object is constructed, you can't see a partially constructed object anywhere. And if you inline the constructor, you better make sure no one else can see that reference, or you're violating the spec.
The one assembly decompilation I've seen that seems to show this was stated to have been generated by an ancient Symantec JIT compiler - not exactly official.
If someone could explain why a modern, approved, OpenJDK compiler can re-order writes to expose a reference to a partially created object, and why that doesn't contradict the spec, I'll bite, but until, this all looks like a bunch of hand-waving generalizations based on experiences with other compilers and specs (and, note, I don't mean revealing a partially constructed object by leaking the this pointer out to an external class - if you do that, you only have yourself to blame).
Upvotes: 1
Reputation: 4286
It can be caused by compiler reorderings. Compiler can inline Flooble
's constructor and change order of initialization of its fields and assigning reference to theFlooble
variable.
Declaring theFlooble
volatile prevents such reorderings.
See https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Upvotes: 3