Cheetah
Cheetah

Reputation: 14379

Is setting this reference thread safe?

I keep getting mixed answers as to whether this code is thread-safe or not. I am working in Java 8.

private final Object lock = new Object();
private volatile Object reference = null;

public Object getOrCompute(Supplier<Object> supplier) {
    if (reference == null) {
        synchronised(lock) {
            if (reference == null) {
                reference = supplier.get();
            }
        }
    }

    return reference;
}

My expectation is that given a new instance of this class, multiple calls to getOrCompute() will only ever result in one supplier being called and the result of that supplier being the result of all calls (and future calls) to getOrCompute().

Upvotes: 3

Views: 182

Answers (2)

biziclop
biziclop

Reputation: 49744

It is safe because whatever is done in supplier.get() must not be reordered with the assignment to reference. (Or to be more precise, it mustn't appear to be reordered when you do a volatile read of reference.)

The lock provides exclusivity and the volatile write/read semantics provide visibility. Note that this has only been true since Java 5, which was released a long-long time ago, but you'll still find outdated articles on the Internet about how double-checked locking (for that's the official name of this idiom) isn't working. They were right at the time but they are obsolete now.

What can be unsafe though is the supplier itself, if it supplies a mutable object. But that's a different matter.

Upvotes: 3

Gemtastic
Gemtastic

Reputation: 6433

Synchronization is not thread safe. It's hindering the threads from accessing the object all at once, but it has no control over which thread gets it when or what it does with the object once it's gained access to it. Synchronization only limits access to one thread at the time, the thread that access it first get to access it first.

In this case, the only thing it does is preventing several threads to instantiate the object. If the object already is instantiated, it will be handed out to whatever thread wants it with no thread safety what so ever.

Imagine you have one thread accessing the method and instantiating the object, it retrieves it and while it's retrieving the object, another thread is trying to instantiate it, which it won't be allowed to since it exist so it can jump straight to retrieving the object, just like thread number one, these can now modify the object at the same time, ergo, not thread safe. But the instantiation of a new object is thread safe in the manner that the object can only be instantiated once.

Upvotes: 0

Related Questions