【问题标题】:ConcurrentHashMap update exists value thread safeConcurrentHashMap 更新存在值线程安全
【发布时间】:2016-07-16 14:54:57
【问题描述】:

我想使用并发散列映射来保存一些结果,

ConcurrentHashMap<Long,AtomicInteger>

如果key不存在,则添加一个新条目,或者通过key获取值并递增,如下所示:

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

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

【问题讨论】:

  • 这不仅仅是 put 操作 - 显示的整个条件块必须在同步块中。或者,您可以使用putIfAbsent
  • 使用 putIfAbsent 似乎更简单。我在同步块中使用了双重检查,而不是在整个条件块中使用。

标签: java multithreading java.util.concurrent


【解决方案1】:

你应该使用ConcurrentHashMap.putIfAbsent(K key, V value)并注意返回值。

【讨论】:

    【解决方案2】:

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

    然而,调用不是,即两个线程可以同时添加一个新键。你可以试试putIfAbsent(),如果你得到一个返回值(即非空)你可以调用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(取决于您对该值所做的其他操作)。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-15
        • 1970-01-01
        • 2012-08-20
        • 2014-03-04
        • 2019-09-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多