ConcurrentHashMap更新存在值线程安全

ConcurrentHashMap update exists value thread safe

我想使用保存一些结果的并发哈希映射,

ConcurrentHashMap<Long,AtomicInteger>

如果键不存在则添加一个新条目,或者通过键和增量获取值,就像这样:

if(map.contains(key))
  map.get(key).addAndGet(1);
else
  map.put(key,new AtomicInteger(1));    

put操作不安全,如何解决这个问题? put 操作应该在 synchronized 块内吗?

您应该使用 ConcurrentHashMap.putIfAbsent(K key, V value) 并注意 return 值。

put() 操作本身是以线程安全的方式实现的,即如果您输入相同的密钥,它将在内部同步。

然而,调用不是,即两个线程可以同时添加一个新密钥。您可以尝试 putIfAbsent(),如果您得到 return 值(即不为空),您可以调用 get 方法。因此,您可以像这样更改代码:

//this only adds a new key-value pair if there's not already one for the key
if( map.putIfAbsent(key,new AtomicInteger(1)) != null ) {    
  map.get(key).addAndGet(1);
}

或者,如果您使用的是 Java 8,则可以使用 compute() 方法,根据 JavaDoc,该方法是自动执行的。然后,您传递的函数将检查该值是否已经存在。由于整个调用是同步的,您可能甚至不需要使用 AtomicInteger(取决于您对值进行的其他操作)。

在 Java 8 中,您可以使用 ConcurrentHashMap 的 computeIfAbsent 来提供初始值:

map.computeIfAbsent(key, new AtomicInteger(0)).addAndGet(1)