Я работаю по пункту 71, "Использовать ленивую инициализацию разумно", "Эффективная Java" (второе издание). Это предполагает использование идиомы двойной проверки для ленивой инициализации полей экземпляра с помощью этого кода (стр. 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;
}
Итак, у меня есть несколько вопросов:
-
Зачем нужен изменчивый модификатор на
field
, если инициализация происходит в синхронизированном блоке? Книга предлагает этот вспомогательный текст: "Поскольку нет блокировки, если поле уже инициализировано, важно, чтобы поле было объявлено изменчивым". Следовательно, так ли это, что после инициализации поля volatile является единственной гарантией множественных согласованных потоков наfield
, учитывая отсутствие другой синхронизации? Если да, почему бы не синхронизировать getField(), или это так, что приведенный выше код обеспечивает лучшую производительность? -
В тексте предлагается, чтобы не требуемая локальная переменная
result
использовалась для "обеспечения того, чтобыfield
читается только один раз в обычном случае, когда он уже инициализирован", тем самым повышая производительность. Еслиresult
был удален, как быfield
было прочитано несколько раз в обычном случае, когда он уже был инициализирован?