我不明白为什么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仍抱怨不是原子的。
它说:
对concurrenthashmap的调用顺序可能不是原子的
将put更改为putIfAbsent
,FindBugs仍然抱怨。
答案 0 :(得分:2)
Findbugs观察到这对方法调用map.get(id)
,map.put(id, obj)
可能不是原子的,这意味着其他一些线程可能会在其间修改map
。
例如,另一个线程可以在这两个调用之间记录键id
的不同映射,然后在第一个线程执行其map.put()
时静默丢失。由于您懒得测试是否最初存在该键的映射,因此该结果似乎不太可接受。
解决此问题的一种方法是使用ConcurrentHashMap.putIfAbsent()
代替两个调用(不只是代替put()
)。
答案 1 :(得分:0)
如果某个其他线程在您的线程正在评估if ()
语句时添加了具有该键的条目,则您的线程将覆盖它。
您需要仅使用putIfAbsent
,否则不要与地图互动。