У меня есть фрагмент кода, который может выполняться несколькими потоками, которому необходимо выполнить операцию с привязкой к вводу-выводу, чтобы инициализировать общий ресурс, который хранится в ConcurrentMap
. Мне нужно сделать этот код потокобезопасным и избежать ненужных вызовов для инициализации общего ресурса. Вот код с ошибкой:
private ConcurrentMap<String, Resource> map;
// .....
String key = "somekey";
Resource resource;
if (map.containsKey(key)) {
resource = map.get(key);
} else {
resource = getResource(key); // I/O-bound, expensive operation
map.put(key, resource);
}
С помощью приведенного выше кода несколько потоков могут проверить ConcurrentMap
и увидеть, что ресурса там нет, и все попытаются вызвать getResource ()
, который дорогой. Чтобы гарантировать только однократную инициализацию общего ресурса и сделать код эффективным после инициализации ресурса, я хочу сделать что-то вроде этого:
String key = "somekey";
Resource resource;
if (!map.containsKey(key)) {
synchronized (map) {
if (!map.containsKey(key)) {
resource = getResource(key);
map.put(key, resource);
}
}
}
Это безопасная версия блокировки с двойной проверкой? Мне кажется, что, поскольку проверки вызываются на ConcurrentMap
, он ведет себя как общий ресурс, который объявлен как изменчивый
, и, таким образом, предотвращает любые проблемы «частичной инициализации», которые могут случиться.