Идиома с одной проверкой может использоваться для реализации потокобезопасного инициализации с (по сравнению с двойной проверкой) возможного недостатка траты некоторое время вычисления несколькими параллельными вводами. ЭтоВнедрение параметризованного поточно-безопасного кэша ленивого инициализации с использованием ConcurrentHashMap (без ключевого слова volatile)
Single-проверка идиом
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) {
field = result = computeFieldValue();
}
return result;
}
Здесь нам нужно летучий 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 (индекс, результат) 'выполняет необходимую синхронизацию (поскольку это запись). Обратите внимание, что вопрос здесь может быть двояким: сначала мне интересно, работает ли это в (а) текущей реализации JVM, во-вторых (что еще более важно), интересно ли это (с учетом документации/контракта) ConcurrentHashMap
.
Примечание: Здесь я предполагаю, что computeItemValue генерирует неизменяемый объект и гарантирует безопасность потока в смысле одноименной идиомы (то есть, когда построение объекта завершено, возвращаемый объект ведет себя одинаково для всех потоков). Я предполагаю, что это статья 71 в книге Дж. Блоха.
Ни одно из ваших предложений является поточно.Несколько потоков могут вызывать 'computeFieldValue' и присваивать значение полю/добавлять его к карте. Для 'ConcurrentHashMap' используйте' putIfAbsent' или 'computeIfAbsent'. –
Они потокобезопасны в смысле одноименной идиомы, что computeFieldValue создает неизменяемый объект, который ведет себя одинаково, даже если он построен несколько раз ... (пожалуйста, единичная идиома в книге Блоха). –
@ChristianFries Правильный одноэлементный шаблон не инициализирует экземпляр более одного раза. – Kayaman