if(concurrentHashMap.containKey(key))
{
// oops, v has been removed in another thread right after current thread
// complete containKey calling
Value v = concurrentHashMap.get(key);
// do something on v // null pointer exception
}
似乎并发集合的包含类方法是无用的,以解决上述问题:
Vaule v = concurrentHashMap.get(key);
if(v != null)
{
// ok, hold v's reference
// do something on v
}
我是对的吗?
答案 0 :(得分:5)
这不是没用的。想象一下,get
的结果不需要做任何事情。在这种情况下,containsKey
和get
都有(并遭受)同样的问题。
正如Voo在评论中指出的那样,代码通常可以用putIfAbsent
(用于表示更大的原子操作)来编写。
只是不(因为它本身不能)创建一个更大的原子上下文。也就是说, nothing 阻止其他线程在concurrentHashMap
和containsKey
之间对get
执行操作。密切关注contract from the javadoc:
...即使所有 [个人] 操作都是线程安全的,但检索操作不需要锁定,并且没有任何支持以一种方式锁定整个表阻止所有访问 ...
检索操作(包括get)一般不会阻塞,因此可能与更新操作重叠(包括put和remove)。 检索[例如containsKey或get]反映了最近完成的更新操作的结果在发病时保留......
“线程安全”对象与在并发上下文中正确使用所述对象之间存在差异。
快乐的编码。
答案 1 :(得分:4)
如评论主题中所述:不,containsKey
不会以任何方式锁定该条目,因此稍后调用get(key)
可能会返回null
。也就是说,如果你只对布尔值感兴趣 - 是地图中的关键吗? - 以后您不需要获取密钥,然后containsKey
就可以了。
此外,containsKey
界面还需要Map
,所以不管怎样它都不会在那里。