+3  A: 

I think this should be safe, but only because you're storing the field in a local variable. After this is done, there's no way for the local variable reference to magically change to null, even if another thread is resetting field's value half-way through.

I was just discussing that with my colleague ... we agreed ...

It seems like this will work as long as the reset method is the reset() method listed above. However, if the reset() method instantiates a new Object (like below), couldn't you end up potentially returning something different than you intended?

void reset() {
    field = new FieldType();
yes, but that type of reset would defeat the whole purpose of the double-check idiom.
+3  A: 

Yes, this is thread safe.

The synchronized block is to prevent multiple threads from unnecessarily calling computeFieldValue(). Since field is volatile, the accesses in reset and getField are all well-ordered.

If the first check is non-null, getField is done; result is returned.

Otherwise, a lock is acquired, excluding any other thread that might set the field to non-null, but permitting any thread to set field to null. If any thread does set field to null, nothing should have changed; that's the condition that got the thread into the synchronized block. If another thread had already acquired the lock after the current thread's check, and set the field to a non-null value, the second check will detect that.


I guess it depends on exactly what you mean by thread-safe.

You could end up with a situation where a first instance is used after a second. That may be okay, or it may not.

Tom Hawtin - tackline