If you need to use lazy initialization for performance on an
instance field, use the double-check
idiom. This idiom avoids the cost
of locking when accessing the field
after it has been initialized (Item
67). 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. Only if the
second check indicates that the field
is uninitialized does the call
initialize the field. Because there is
no locking if the field is already
initialized, it is critical that the
field be declared volatile
(Item
66). Here is the 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)
return result;
synchronized(this) {
if (field == null) // Second check (with locking)
field = computeFieldValue();
return field;
}
}
This code may appear a bit convoluted.
In particular, the need for the local
variable result may be unclear. What
this variable does is to ensure that
field is read only once in the common
case where it’s already initialized.
While not strictly necessary, this may
improve performance and is more
elegant by the standards applied to
low-level concurrent programming. On
my machine, the method above is about
25 percent faster than the obvious
version without a local variable.
Prior to release 1.5, the double-check
idiom did not work reliably because
the semantics of the volatile modifier
were not strong enough to support it
[Pugh01]. The memory model introduced
in release 1.5 fixed this problem
[JLS, 17, Goetz06 16]. Today, the
double-check idiom is the technique of
choice for lazily initializing an
instance field. While you can apply
the double-check idiom to static
fields as well, there is no reason to
do so: the lazy initialization holder
class idiom is a better choice.