private SomeObject obj; public SomeObject getObject() { if (obj == null) obj = computeObjectValue(); return obj; }
Such a code is pretty simple, but requires synchronization in case of concurrent access. Adding
synchronized
keyword to getObject
method is sufficient to avoid repeated initialization for instance and static fields, but harms performance. That's why it is good to use several idioms proposed by Joshua Bloch.Single-check idiom
private volatile SomeObject obj; public SomeObject getObject() { SomeObject result = obj; if(result == null) obj = result = computeObjectValue(); return result; }When to use: if an instance field can tolerate repeated initialization
Why field needs to be volatile: it adds synchronization on the field; in case of primitives other than long or double
volatile
can be removed, but in this situation we will face more repeated initializations caused by caching field value by VMWhy to use additional local variable result: access to volatile field is slower than to this variable
Double-check idiom
private volatile SomeObject obj; public SomeObject getObject() { SomeObject result = obj; if (result == null) { synchronized (this) { result = obj; if (result == null) obj = result = computeObjectValue(); } } return result; }When to use: if an instance field should be initialized only once.
Why double check field: in this solution we postpone synchronization to the very last moment, first check is outside synchronized block, so we need to do it again.
Holder class idiom
public static SomeObject getObject() { return FieldHolder.obj; } private static class FieldHolder { private static final SomeObject obj = computeObjectValue(); }When to use: if you want to lazy initialize static field
Why to use additional class: it is guaranteed that classes will not be initialized until it is used. VM synchronize field access only to initialize the class. When field is subsequently accessed VM patches the code, so no testing or synchronization is involved.