Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resetting a field lazy-loaded with the double-check idiom

Consider the "double-check idiom for lazy initialization of instance fields":

// Item 71 in Effective Java copied from this interview with Bloch.
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
     return result;
}

I want to be able to reset the field in a safe way (force it to load again from the database, in my case). I assume that we could do this by having a reset method:

void reset() {
   field = null;
}

Is this the standard way of doing resetting the field? Is it safe? Any pitfalls? I'm asking because Bloch gave the following warning about double-checked lazy-loading: "The idiom is very fast but also complicated and delicate, so don't be tempted to modify it in any way. Just copy and paste -- normally not a good idea, but appropriate here."

Thanks in advance, Playa from the Himalayas.

like image 507
les2 Avatar asked Nov 20 '08 22:11

les2


2 Answers

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.

like image 78
erickson Avatar answered Nov 15 '22 03:11

erickson


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.

like image 38
InverseFalcon Avatar answered Nov 15 '22 02:11

InverseFalcon