11

Can in the following conceptual Java example:

public class X implements Runnable {
    public volatile Object x = new Object();

    @Runnable
    public void run() {
        for (;;) {
            Thread.sleep(1000);
            x = new Object();
        }
    }
}

x ever be read as null from another thread?

Bonus: Do I need to declare it volatile (I do not really care about that value, it suffices that sometime in the future it will be the newly assigned value and never is null)

scravy
  • 11,904
  • 14
  • 72
  • 127

3 Answers3

4

Technically, yes it can. That is the main reason for the original ConcurrentHashMap's readUnderLock. The javadoc even explains how:

Reads value field of an entry under lock. Called if value field ever appears to be null. This is possible only if a compiler happens to reorder a HashEntry initialization with its table assignment, which is legal under memory model but is not known to ever occur.

Since the HashEntry's value is volatile this type of reordering is legal on consturction.

Moral of the story is that all non-final initializations can race with object construction.


Edit: @Nathan Hughes asked a valid question:

@John: in the OP's example wouldn't the construction have happened before the thread the runnable is passed into started? it would seem like that would impose a happens-before barrier subsequent to the field's initialization.

Doug Lea had a couple comments on this topic, the entire thread can be read here. He answered the comment:

But the issue is whether assignment of the new C instance to some other memory must occur after the volatile stores.

With the answer

Sorry for mis-remembering why I had treated this issue as basically settled: Unless a JVM always pre-zeros memory (which usually not a good option), then even if not explicitly initialized, volatile fields must be zeroed in the constructor body, with a release fence before publication. And so even though there are cases in which the JMM does not strictly require mechanics preventing publication reordering in constructors of classes with volatile fields, the only good implementation choices for JVMs are either to use non-volatile writes with a trailing release fence, or to perform each volatile write with full fencing. Either way, there is no reordering with publication. Unfortunately, programmers cannot rely on a spec to guarantee it, at least until the JMM is revised.

And finished with:

  • Programmers do not expect that even though final fields are specifically publication-safe, volatile fields are not always so.

  • For various implementation reasons, JVMs arrange that volatile fields are publication safe anyway, at least in cases we know about.

  • Actually updating the JMM/JLS to mandate this is not easy (no small tweak that I know applies). But now is a good time to be considering a full revision for JDK9.

  • In the mean time, it would make sense to further test and validate JVMs as meeting this likely future spec.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • So what's the solution for the _hoi polloi_ (i.e. me)? Instead of `volatile`, use `final AtomicReference`? – Erick G. Hagstrom Dec 17 '15 at 19:55
  • 1
    A `final AtomicReference` would certainly solve the issue you would have with a `volatile` field. Based on DL's answer and past discussion, I would hope JDK 9 will introduce an updated JMM preventing this type of reordering. He also mentions how unlikely it is to occur. – John Vint Dec 17 '15 at 20:03
2

This depends on how the X instance is published.

Suppose x is published unsafely, eg. through a non-volatile field

private X instance;
...
void someMethod() {
    instance = new X();
}

Another thread accessing the instance field is allowed to see a reference value referring to an uninitialized X object (ie. where its constructor hasn't run yet). In such a case, its field x would have a value of null.

The above example translates to

temporaryReferenceOnStack = new memory for X // a reference to the instance
temporaryReferenceOnStack.<init> // call constructor
instance = temporaryReferenceOnStack;

But the language allows the following reordering

temporaryReferenceOnStack = new memory for X // a reference to the instance
instance = temporaryReferenceOnStack;
temporaryReferenceOnStack.<init> // call constructor

or directly

instance = new memory for X // a reference to the instance
instance.<init> // call constructor

In such a case, a thread is allowed to see the value of instance before the constructor is invoked to initialize the referenced object.

Now, how likely this is to happen in current JVMs? Eh, I couldn't come up with an MCVE.


Bonus: Do I need to declare it volatile (I do not really care about that value, it suffices that sometime in the future it will be the newly assigned value and never is null)

Publish the enclosing object safely. Or use a final AtomicReference field which you set.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
1

No. The Java memory model guarantees that you will never seen x as null. x must always be the initial value it was assigned, or some subsequent value.

This actually works with any variable, not just volatile. What you are asking about is called "out of thin air values". C.f. Java Concurrency in Practice which talks about this concept in some length.

The other part of your question "Do I need to declare x as volatile:" given the context, yes, it should be either volatile or final. Either one provides safe publication for your object referenced by x. C.f. Safe Publication. Obviously, x can't be changed later if it's final.

Community
  • 1
  • 1
markspace
  • 10,621
  • 3
  • 25
  • 39
  • 1
    Per the JLS 8, 17.4.4 Synchronization Order: "A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order)." Seems like that supports the answer. – Erick G. Hagstrom Dec 17 '15 at 18:36
  • 1
    The down-voter may be thinking of a "this-escape" which makes an object visible before construction is complete. However, this object has no declared ctor, so a this-escape is not possible. – markspace Dec 17 '15 at 18:38
  • 1
    Personally, I use this pattern all the time, although I use `final` not `volatile`. It's a good pattern, pity and works in nearly all cases. – markspace Dec 17 '15 at 18:40
  • @Markspace I think technically the answer to the question itself (as opposed to the code given in it) is: "Yes, if the class was `Serializable` and the field was also marked as `transient` and you had just deserialized it". Then you'd never _see_ it being set to `null` if you grepped the code, but it would be set to `null` during the de-serialization. – Sled Dec 17 '15 at 18:45
  • 1
    The write to a volatile field can race with construction as my answer states *This is possible only if a compiler happens to reorder a HashEntry initialization with its table assignment, which is legal under memory model but is not known to ever occur.* – John Vint Dec 17 '15 at 19:07
  • @John: in the OP's example wouldn't the construction have happened before the thread the runnable is passed into started? it would seem like that would impose a happens-before barrier subsequent to the field's initialization. – Nathan Hughes Dec 17 '15 at 19:13
  • It definitely would have imposed a memory barrier, but there is no guarantees in Java that the barrier is issued prior to the constructor completing. So at that point you lose any happens-before ordering. I can explain more on my answer. – John Vint Dec 17 '15 at 19:21