回到并发。现在很明显,要使double checked locking
变量工作,需要将变量声明为volatile
. 但是,如果如下使用双重检查锁定会怎样。
class Test<A, B> {
private final Map<A, B> map = new HashMap<>();
public B fetch(A key, Function<A, B> loader) {
B value = map.get(key);
if (value == null) {
synchronized (this) {
value = map.get(key);
if (value == null) {
value = loader.apply(key);
map.put(key, value);
}
}
}
return value;
}
}
为什么它真的必须是ConcurrentHashMap而不是常规的HashMap?所有地图修改都在synchronized
块内完成,代码不使用迭代器,因此从技术上讲不应该存在“并发修改”问题。
请避免建议使用putIfAbsent
/computeIfAbsent
因为我在询问这个概念而不是使用 API :) 除非使用此 API 有助于HashMap
vsConcurrentHashMap
主题。
2016-12-30 更新
Holger 在下面的评论中回答了这个问题“HashMap.get
不会修改结构,但您的调用会修改put
。由于get
在同步块之外调用,它可以看到put
同时发生的操作的不完整状态。” 谢谢!