我有一段代码可以由多个线程执行,需要执行 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);
}
使用上面的代码,多个线程可能会检查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
因此可以防止任何可能发生的“部分初始化”问题。