使用ConcurrentMap双重检查锁定

pmc*_*255 12 java concurrency synchronization double-checked-locking

我有一段代码可以由多个线程执行,需要执行I/O绑定操作,以初始化存储在一个中的共享资源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);
    }
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,多个线程可以检查ConcurrentMap并查看资源不存在,并且所有尝试调用getResource()哪个都很昂贵.为了确保共享资源只进行一次初始化,并在资源初始化后使代码有效,我想做这样的事情:

    String key = "somekey";
    Resource resource;
    if (!map.containsKey(key)) {
        synchronized (map) {
            if (!map.containsKey(key)) {
                resource = getResource(key);
                map.put(key, resource);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是双重检查锁定的安全版本吗?在我看来,自从调用检查以来ConcurrentMap,它的行为类似于声明的共享资源,volatile从而防止可能发生的任何"部分初始化"问题.

irr*_*ble 3

是的,很安全。

map.containsKey(key)根据文档,如果为真,map.put(key, resource)则发生在它之前。所以getResource(key)发生之前resource = map.get(key),一切都安然无恙。