Rule 6:Use Lazy initialization carefully
It delays initialization of field untill it is needed.
This technique is applicable to both static and instance fields.
While lazy initialization is primarily an optimization, it can also be used to break harmful circularities(prob bcoz of overridable method call in super-constrctor) in class and instance initialization.
In the presence of multiple threads, lazy initialization is tricky. If two or more
threads share a lazily initialized field, it is critical that some form of synchronization
be employed, or severe bugs can result.
Follwoing are the initialization techniques discussed in this item that are thread-safe:
1.Under most circumstances, NORMAL INITIALIZATION is preferable to lazy initialization
// Normal initialization of an instance field
private final FieldType field = computeFieldValue();
Note the use of the final modifier(Rule : Classes and Interface – Minimize mutability)
2.If you use LAZY INITIALIZATION to break an initialization circularity and for PERFORMANCE GOALS, use a
SYNCHRONISED ACCESSOR because it is the simplest, clearest alternative:
// Lazy initialization of instance field – synchronized accessor
private FieldType field;
private synchronized FieldType getField() {
if (field == null)
field = computeFieldValue();
Both of these idioms (normal initialization and lazy initialization with a
synchronized accessor) are unchanged when applied to static fields, except that
you add the static modifier to the field and accessor declarations.
3.If you need to use lazy initialization for performance on a STATIC FIELD, use
the LAZY INITIALIZATION Holder Class Idiom.
This idiom exploits the guarantee that a class will not be initialized until it is used
// Lazy initialization holder class idiom for static fields.
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
private static FieldType getField() { return FieldHolder.field; }
- If you need to use LAZY INITIALIZATION for performance on AN INSTANCE FIELD,
use the DOUBLE-CHECK idiom.
// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
private FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
if (field == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
The idea behind the idiom is to check the value of the field twice (hence the name double-check): once without
locking and then, if the field appears to be uninitialized, a second time with locking.
you can use a variant of the double-check idiom
that dispenses with the second check IF lazily initialize an instance field that can tolerate repeated initialization.
// Single-check idiom – can cause repeated initialization!
private volatile FieldType field;
private FieldType getField() {
FieldType result = field;
if (result == null)
field = result = computeFieldValue();
return result;
}
In summary,
you should initialize most fields normally, not lazily. If you must
initialize a field lazily in order to achieve your performance goals or to break a
harmful initialization circularity, then use the appropriate lazy initialization
technique.
For instance fields, it is the double-check idiom; for static fields, the
lazy initialization holder class idiom. For instance fields that can tolerate repeated
initialization, you may also consider the single-check idiom.