Bambelal
Bambelal

Reputation: 179

Java concurrency in practice - safe publication, immutable object and volatile

I'm reading "Java concurrency in practice" and one thing is confusing me.

class OneValueCache {
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;

    public OneValueCache(BigInteger lastNumber, BigInteger[] lastFactors) {
        this.lastNumber = lastNumber;
        this.lastFactors = Arrays.copyOf(lastFactors, lastFactors.length);
    }

    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i)) {
            return null;
        }
        return Arrays.copyOf(lastFactors, lastFactors.length);
    }
}

class VolatileCachedFactorized implements Servlet {
    private volatile OneValueCache cache = new OneValueCache(null, null);

    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = cache.getFactors(i);

        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, factors);
        }

        encodeIntoResponse(resp, factors);
    }
}

In above code author uses volatile with reference to immutable OneValueCache, but a few page later he writes:

Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.

So .. volatile is not necessary in above code?

Upvotes: 1

Views: 134

Answers (2)

Shailendra
Shailendra

Reputation: 9102

There are kind of 2 level of "thread-safety" that is being applied here. One is at reference level ( done using volatile). Think of an example where a thread reads the value to be null vs other thread seeing some reference value ( changed in between). Volatile will guarantee the publication of one thread is visible to another. But aAnother level of thread safety will be required to safeguard the internal members themselves which have the potential to be changed. Just having a volatile will have no impact on the data within the Cache ( like lastNumber, lastFactors). So immutability will help in that case.

As a general rule ( referred here) as a good thread safe programming practice

Do not assume that declaring a reference volatile guarantees safe publication of the members of the referenced object

This is the same reason why putting a volatile keyword in front of a HasMap variable does not make it threadsafe.

Upvotes: 2

iggy
iggy

Reputation: 1328

cache is not a cache, it is a reference to a cache. The reference needs to be volatile in order that the switch of cache is visible to all threads.

Even after assignment to cache, other threads may be using the old cache, which they can safely do. But if you want the new cache to be seen as soon as it is switched, volatile is needed. There is still a window where threads might be using the old cache, but volatile guarantees that subsequent accessors will see the new cache. Do not confuse 'safety' with 'timeliness'.

Another way to look at this is to note that immutability is a property of the cache object, and cannot affect the use of any reference to that object. (And obviously the reference is not immutable, since we assign to it).

Upvotes: 0

Related Questions