Search code examples
javaconcurrencyvolatilejava.util.concurrent

Does using volatile to publish immutable objects are safe?


Recently I read "Java concurrency in practice" Section --> "3.4.2 Example: Using volatile to publish immutable objects".

However; I can't quietly understand it. Here is the situation!

Immutable object is:

@Immutable
class OneValueCache {
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;
    public OneValueCache(BigInteger i, BigInteger[] factors) {
        lastNumber = i;
        lastFactors = Arrays.copyOf(factors, factors.length);
    }
    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i))
            return null;
        else
            return Arrays.copyOf(lastFactors, lastFactors.length);
    }
}

Suppose we have a servlet like this

public class MyServlet {
private volatile OneValueCache immutableValue;
.
.

public void service(){
            .
            // what this function do : gets value from immutable object increments its
            // value and creates new Immutable object and put it back.
            // 
            .
    immutableValue = new OneValueCache( lastNumber, lastFactor[]);
    .
    .
    .
}
.
.
.
}

According the book MyServlet is Thread Safe because it publishes Immutable Object with volatile keyword!

However I think there is a problem here!

Suppose:

Thread 1 in time 0 read the values from immutableValue to its stack var;

Thread 2 in time 0 read the values from immutableValue to its stack var;

Thread 1 in time 1 increment the values in stack variable and create new OneValueCache object -which is immutable - and put it in immutableValue field variable;

Thread 2 in time 2 increment the values in stack variable and create new OneValueCache object -which is immutable - and put it in immutableValue field variable;

This way we lost Thread1 update so there is no ThreadSafty here!

On the contrary the book says:

" This combination of an immutable holder object for multiple state variables related by an invariant, and a volatile reference used to ensure its timely visibility, allows VolatileCachedFactorizer to be thread-safe even though it does no explicit locking. "

Can anyone help me what am I missing here?

p.s: to more clarify, I know data consistency is held here. we can not have invalid OneValueCache state. but there is a chance for lost update here as my thread sequence shows. so the class is not thread safe!


Solution

  • Immutability implies thread safety because once created no thread can modify it, so value will remain consistent across threads.

    In the above example "private volatile OneValueCache immutableValue" can hold only one value at a time , so if thread 1 updated first and then thread 2 updated reference value then the last value will represented by "onevaluecache" and update of Thread 1 will be lost as you are storing only one reference value.

    At no point in steps mentioned by you state of OneValueCache is inconsistent, so it is thread safe.

    EDIT: Some of Cases where state will not be consistent are:

    1. If immutableValue variable was not volatile then each thread will store its own copy, which means cache will not work properly.

    2. If OneValueCache class was mutable then mutiple threads will look to change its value simultaneously which means state will not be consistent hence not thread safe.