FindBugs 对 ConcurrentHashMap 的调用序列可能不是原子的
FindBugs sequence of calls to ConcurrentHashMap may not be atomic
我不明白为什么 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 仍然抱怨。
如果在您的线程正在评估 if ()
语句时其他线程使用该键添加条目,您的线程将覆盖它。
您需要使用 putIfAbsent
仅,否则不能与地图互动。
Findbugs 观察到这对方法调用 map.get(id)
、map.put(id, obj)
可能不是原子的,这意味着其他线程可能会在两者之间修改 map
。
例如,另一个线程可能会记录这两个调用之间键 id
的不同映射,然后当第一个线程执行它的 map.put()
时,它会悄无声息地丢失。由于您费心测试该键最初是否存在映射,因此这个结果似乎不太可能是可以接受的。
解决此问题的一种方法是使用 ConcurrentHashMap.putIfAbsent()
代替 both 调用(而不仅仅是代替 put()
)。
我不明白为什么 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 仍然抱怨。
如果在您的线程正在评估 if ()
语句时其他线程使用该键添加条目,您的线程将覆盖它。
您需要使用 putIfAbsent
仅,否则不能与地图互动。
Findbugs 观察到这对方法调用 map.get(id)
、map.put(id, obj)
可能不是原子的,这意味着其他线程可能会在两者之间修改 map
。
例如,另一个线程可能会记录这两个调用之间键 id
的不同映射,然后当第一个线程执行它的 map.put()
时,它会悄无声息地丢失。由于您费心测试该键最初是否存在映射,因此这个结果似乎不太可能是可以接受的。
解决此问题的一种方法是使用 ConcurrentHashMap.putIfAbsent()
代替 both 调用(而不仅仅是代替 put()
)。