Konstantin Milyutin
Konstantin Milyutin

Reputation: 12366

Understanding JVM guarantees for immutable objects

Java Concurrency in Practice has the following example:

@ThreadSafe
public class VolatileCachedFactorizer 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);
        }
    }
}

The OneValueCache is immutable.

From what I understand using volatile ensures that all threads see up-to-date reference stored in the cache variable.

At the same time it says that

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

For me it says that we actually don't need that volatile above that we used for synchronization.

JLS also has the following example:

class FinalFieldExample {
    final int x;
    int y; 

    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3;
        y = 4;
    }

    static void writer() {
        f = new FinalFieldExample();
    }

    static void reader() {
        if (f != null) {
            int i = f.x; // guaranteed to see 3
            int j = f.y; // could see 0
        }
    }
}

They don't use volatile for field f. Doesn't it mean that other threads can see f as null and never see the created instance?

Could someone explain?

Upvotes: 2

Views: 357

Answers (1)

dudel
dudel

Reputation: 692

From what I understand using volatile ensures that all threads see up-to-date reference stored in the cache variable.

That's right, but this concept applies to the variable while the statement quoted from JCiP

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

does not apply to a variable but to the object itself. It means that a thread will always see a fully constructed object without any data races independent on how it is published because as JCiP states

Immutable objects can be published through any mechanism.

Now in regard to your second example:

Doesn't it mean that other threads can see f as null and never see the created instance?

That is right. If one thread calls writer() other thready may see f as null or f.y as 0 because it does not respect safe publication:

3.5.3. Safe Publication Idioms

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  • Initializing an object reference from a static initializer;
  • Storing a reference to it into a volatile field or AtomicReference;
  • Storing a reference to it into a final field of a properly constructed > object; or
  • Storing a reference to it into a field that is properly guarded by a lock.

Upvotes: 2

Related Questions