我不明白为什么 FindBug 会提示这段代码
Foo obj = map.get(id);
if(obj == null) {
obj = new Foo();
map.put(id, obj);
}
obj.add(someObject);
第二个版本
Foo tmp = new Foo();
obj = map.putIfAbsent(id, tmp);
if (obj == null)
obj = tmp
obj.add(someObject);
如果我做第二个版本,我每次都必须创建 Foo
对象。
Foo obj = map.get(id);
if(obj == null) {
lock.writeLock().lock();
try {
obj = new Foo();
map.put(id, obj);
}finally {
lock.writeLock().unlock();
}
}
obj.add(someObject);
在第三个版本中,FindBugs 仍然提示不是原子的。
它说:
Sequence of calls to concurrenthashmap may not be atomic
将 put 更改为 putIfAbsent
,FindBugs 仍然提示。
最佳答案
Findbugs 观察到一对方法调用 map.get(id)
、map.put(id, obj)
可能不是原子的,这意味着它有可能其他线程在其间修改 map
。
例如,另一个线程可能会在这两个调用之间记录不同的键 id
映射,然后当第一个线程执行其 map.put()
时,该映射会默默丢失>。由于您费心测试该键最初是否存在映射,因此该结果似乎不太可能是可接受的。
解决此问题的一种方法是使用 ConcurrentHashMap.putIfAbsent()
代替两个调用(不仅仅是代替 put()
)。
关于java - FindBugs 对 ConcurrentHashMap 的调用序列可能不是原子的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29657960/