[英]Java ConcurrentHashMap atomic get if present
如何在并发哈希映射上执行安全获取操作? (与putIfAbsent相同)
不好的例子,不是非常线程安全(检查然后行为情况):
ConcurrentMap<String, SomeObject> concMap = new ...
//... many putIfAbsent and remove operations
public boolean setOption(String id, Object option){
SomeObject obj = concMap.get(id);
if (obj != null){
//what if this key has been removed from the map?
obj.setOption(option);
return true;
}
// in the meantime a putIfAbsent may have been called on the map and then this
//setOption call is no longer correct
return false;
}
另一个糟糕的例子是:
public boolean setOption(String id, Object option){
if (concMap.contains(id)){
concMap.get(id).setOption(option);
return true;
}
return false;
}
这里需要的是不要通过同步来阻止添加,删除和获取操作。
谢谢
ConcurrentHashMap
上的get()
方法是原子的。 由于该映射不允许空值,因此get()
实现“get if present”:如果结果为null
,则该键不存在。
不要使用containsKey
/ get
,只需调用get
。 如果该方法返回null
则该键不存在,否则键存在,并且您获得了在get
时映射到的值。
来自文档:
返回指定键映射到的值,如果此映射不包含键的映射,则返回null。
这是你的第二个例子应该是这样的:
public boolean setOption(String id, Object option) {
SomeObject opt = concMap.get(id);
if (opt == null)
return false;
opt.setOption(option);
return true;
}
您似乎要做的是将密钥锁定在多个操作上。 只有每个操作都是原子的。 这些不是锁定密钥的简单方法,只是锁定地图。
但是在“如果我删除密钥”的情况下,您可以做的就是延迟删除操作,直到调用setOption为止。 结果应该是一样的。
您似乎试图解决可能不需要解决的问题。 您还没有解释为什么在删除密钥后或者等待删除密钥时调用setOption是不好的。
如果需要对ConcurrentMap中的单个键执行多个操作,可以使用Lock striping技术来减少争用,这是Guava框架的一个示例:
private Striped<Lock> lock;
public boolean setOption(String id, Object option) {
try {
Lock lock = concMap.get(id);
lock.lock();
if (concMap.contains(id)){
concMap.get(id).setOption(option);
return true;
}
return false;
} finally {
lock.unlock();
}
}
或者,既然Java 8:ConcurrentMap.compute是一个新的原子方法,请查看它是如何在一个键上完成的:
concMap.compute(keyId, (key, value) -> {
dosmth; ... return key; });
ps可能的变化是ConcurrentMap.computeIfPresent()等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.