H2ONaCl
H2ONaCl

Reputation: 11279

one-time safe publication via a Java volatile

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

Answers (2)

user2077221
user2077221

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

Vladimir Petrakovich
Vladimir Petrakovich

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

Related Questions