Идиома с одиночной проверкой может использоваться для реализации ленивой инициализации, безопасной для потоков, с (по сравнению с двойной проверкой) возможным недостатком, заключающимся в трате некоторого времени вычислений на несколько параллельных инициализаций. это
Идиома одиночной проверки
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) {
field = result = computeFieldValue();
}
return result;
}
Здесь нам нужен volatile field
, чтобы избежать передачи частично инициализированного объекта в другой поток, то есть — присваивание (запись) неявно выполняет необходимую синхронизацию.
Я хотел бы реализовать параметризованный кеш отложенной инициализации, который по сути представлен Map<Integer, Object>
, где каждый элемент создается с использованием отложенной инициализации.
Мой вопрос: достаточно ли использовать ConcurrentHashMap
, чтобы избежать проблемы с частичной инициализацией. То есть в этом случае поточно-безопасная реализация кеша с отложенной инициализацией с использованием идиомы одиночной проверки может быть задана следующим образом:
private final ConcurrentHashMap<Integer, ItemType> items = new ConcurrentHashMap<Integer, ItemType>();
ItemType getItem(Integer index) {
ItemType result = items.get(index);
if (result == null) {
result = computeItemValue(index);
items.put(index, result);
}
return result;
}
Другими словами: я предполагаю, что «items.put(index, result)» выполняет необходимую синхронизацию (поскольку это запись). Обратите внимание, что вопрос здесь может быть двояким: во-первых, мне интересно, работает ли это в (а) текущей реализации JVM, во-вторых (что более важно), интересно, гарантируется ли это (с учетом документации/контракта) ConcurrentHashMap
.
Примечание. Здесь я предполагаю, что calculateItemValue генерирует неизменяемый объект и гарантирует безопасность потока в смысле идиомы одиночной проверки (то есть, после завершения построения объекта возвращаемый объект ведет себя одинаково для всех потоков). Я предполагаю, что это пункт 71 в книге Дж. Блоха.
computeFieldValue
и присваивать значение полю/добавлять его на карту. ДляConcurrentHashMap
используйтеputIfAbsent
илиcomputeIfAbsent
. - person Sotirios Delimanolis   schedule 11.08.2015