【问题标题】:How to populate concurrenthashmap from multiple threads?如何从多个线程填充并发哈希图?
【发布时间】:2015-06-19 02:31:26
【问题描述】:

我有一个从多个线程填充的 ConcurrentHashMap。

private static Map<DataCode, Long> errorMap = new ConcurrentHashMap<DataCode, Long>();

public static void addError(DataCode error) {
    if (errorMap.keySet().contains(error)) {
        errorMap.put(error, errorMap.get(error) + 1);
    } else {
        errorMap.put(error, 1L);
    }
}

我上面的addError 方法是从填充errorMap 的多个线程调用的。我不确定这是否是线程安全的?我在这里做错什么了吗?

任何关于它为什么可以跳过更新的解释都会帮助我更好地理解。

【问题讨论】:

    标签: java multithreading thread-safety concurrenthashmap


    【解决方案1】:

    这是否安全取决于您的意思。它不会抛出异常或破坏地图,但它可以跳过更新。考虑:

    1. Thread1:errorMap.get(error) 返回 1
    2. Thread2:errorMap.get(error) 返回 1
    3. 线程1:errorMap.put(error, 1+1);
    4. 线程2:errorMap.put(error, 1+1);

    围绕keySet().contains(error) 操作存在类似的竞争。要解决此问题,您需要使用原子操作来更新地图。

    在 Java 8 上,这很简单:

    errorMap.compute(error, oldValue -> oldValue == null ? 1L : oldValue + 1L);
    

    在旧版本的 Java 上,您需要使用比较和更新循环:

    Long prevValue;
    boolean done;
    do {
      prevValue = errorMap.get(error);
      if (prevValue == null) {
        done = errorMap.putIfAbsent(error, 1L);
      } else {
        done = errorMap.replace(error, prevValue, newValue);
      }
    } while (!done);
    

    使用此代码,如果两个线程竞争,其中一个可能最终会重试其更新,但它们最终会得到正确的值。

    或者,您也可以使用 Guava 的 AtomicLongMap,它为您完成所有线程安全魔法并获得更高的性能(通过避免所有这些装箱操作等):

    errorAtomicLongMap.incrementAndGet(error);
    

    【讨论】:

    • 感谢您的帮助。现在说得通了。如果可能的话,你能提供一个例子我如何使用 Guava AtomicLongMap 来做这个吗?
    • @david,添加示例。很简单,不是吗? :)
    • 什么?这很简单..太棒了。另外,现在errorAtomicLongMap 声明会是什么样子?我用 AtomicLongMap 替换了 map,出现错误。
    • 这并不是完全的替代品。您需要将其声明为 AtomicLongMap&lt;DataCode&gt;,并在读取时使用 get(error).asMap() 方法
    • 我明白了,当我这样尝试时,我仍然得到一个错误:The constructor AtomicLongMap&lt;DataCode&gt;() is undefined。这就是我正在尝试的:private static AtomicLongMap&lt;DataCode&gt; errorHolder = new AtomicLongMap&lt;DataCode&gt;();我以前从未使用过这个,所以有一些疑问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多