У меня есть часть кода, которая может быть выполнена несколькими потоками, которые должны выполнить операцию привязки ввода-вывода, чтобы инициализировать общий ресурс, который хранится в 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, он ведет себя как общий ресурс, объявленный как volatile и, таким образом, предотвращает любую из проблем "частичной инициализации", которые могут произойти.