I'm working my way through item 71, "Use lazy initialization judiciously", of Effective Java (second edition). It suggests the use of the double-check idiom for lazy initialization of instance fields using this code (pg 283):
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;
}
So, I actually have several questions:
Why is the volatile modifier required on
fieldgiven that initialization takes place in a synchronized block? The book offers this supporting text: "Because there is no locking if the field is already initialized, it is critical that the field be declared volatile". Therefore, is it the case that once the field is initialized, volatile is the only guarantee of multiple thread consistent views onfieldgiven the lack of other synchronization? If so, why not synchronize getField() or is it the case that the above code offers better performance?The text suggests that the not-required local variable,
result, is used to "ensure thatfieldis read only once in the common case where it's already initialized", thereby improving performance. Ifresultwas removed, how wouldfieldbe read multiple times in the common case where it was already initialized?