Двойная проверка блокировки с помощью ConcurrentMap

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

12
задан pmc255 9 August 2011 в 21:27
поделиться