Lazy
initialization - It decreases the cost of initializing a class or
creating an instance, at the expense of increasing the cost of accessing the
lazily initialized field. Depending on what fraction of lazily initialized
fields eventually require initialization, how expensive it is to initialize
them, and how often each field is accessed, lazy initialization can (like many
"optimizations") actually harm performance.
The only way to know
for sure is to measure the performance of the class with and without lazy
initialization.
Principle
- Normal initialization of an instance
field - Under most circumstances, normal initialization is preferable
to lazy initialization.// Normal initialization of an instance
fieldprivate final FieldType field =
computeFieldValue(); - synchronized accessor - If
you use lazy initialization to break an initialization circularity, use a
synchronized accessor, as it is the simplest, clearest
alternative:// Lazy initialization of instance
field - synchronized accessorprivate FieldType field;
synchronized FieldType
getField() {if (field == null)
field =
computeFieldValue();return field;
}
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. - lazy initialization holder class
idiom - If you need to use lazy initialization for performance on a
static field, use the lazy initialization holder class idiom .// Lazy initialization holder class
idiom for static fieldsprivate static class
FieldHolder {static
final FieldType field = computeFieldValue();}
static FieldType getField() {
return FieldHolder.field; } - Double-check idiom - 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 fieldsprivate 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;
}
- Single-check idiom -
Occasionally, you may need to 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;
}
Note
When the double- check or single-check idiom is
applied to a numerical primitive field, the field‘s value is checked against 0
(the default value for numerical primitive variables) rather than
null. - Racy single-check idiom - If
you don‘t care whether every thread recalculates the value of a field, and the
type of the field is a primitive other than long or double , then you may
choose to remove the volatile modifier from the field declaration in the
single-check idiom(e.g. String instances to cache their hash codes).// racy single-check idiom - can cause repeated
initialization!private FieldType field;
private FieldType getField() {
FieldType result =
field;if (result == null)
field = result =
computeFieldValue();return result;
}
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.
心若在,梦就在,布布扣,bubuko.com