Search code examples
javavolatile

A little clarification on the volatile keyword


Consider the snippet from Java Concurrency in Practice-

// Unsafe publication
public Holder holder;

public void initialize(){
    holder = new holder(42);
}

public class Holder{
    private int n;

    public Holder(int n) {
        this.n = n;
    }

    public void assertSanity(){
        if (n != n)
            throw new AssertionError("This statement is false.");
    }
}

One of the solutions suggested by the author of the book is -

public static Holder holder = new Holder(42);

And if the only requirement was to prevent the AssertionError, then this would also work fine-

private final int n;

My question is a follow-up to the comment on this stackoverflow thread by John Vint-

Actually, declaring the member field volatile still doesnt guarantee publication prior to holder being visible. You can look at ConcurrentHashMap's private method readUnderLock in which that takes this nuance into account. Though declaring holder as volatile does.

To put it in simple words, he is suggesting hereby 2 things-

public volatile Holder holder;

public void initialize(){
    holder = new holder(42);
}

Is the above solution going to work perfectly? If a reference to an object is declared as volatile, does it ensures safe object publication? Arrays are objects too. Declaring an array reference doesn't makes its elements thread safe.

And Why this will not work as suggested by author-

public class Holder {
private volatile int n;

declaring the member field volatile still doesnt guarantee publication prior to holder being visible

Even though as the member field has been declared as volatile, its gauranteed that the condition n != n will be always false, and hence no AssertionError. Please suggest.


Solution

  • While using volatile would help as you suggest, it would not help in many other situations you might happen to try to use. i.e. it's very easy to use volatile incorrectly so it would be difficult to encourage unless you can be sure you know which operations will be used.

    If a reference to an object is declared as volatile, does it ensures safe object publication?

    This is very dependant on the order and type of operations. In this case, the write

    this.n = n;
    // and then
    holder = ...
    

    The write to holder ensure the write to this.n must be visible assuming you also do

    Holder h = holder; // read barrier
    // n must be set.
    int n = this.n;
    

    declaring the member field volatile still doesnt guarantee publication prior to holder being visible

    I don't agree in this case. Once you have obtained the holder in another thread, there is no chance that reading n will fail to see the value initialised as you are reading a volatile variable. This is because the holder is set only after n is initialised.