如何在多线程应用程序中自动更新 ConcurrentMap 的值?

How to atomically update the value of ConcurrentMap in multithreaded application?

我有一个 ConcurrentMap,我需要从多线程应用程序中填充它。我的地图如下所示:

  private final ConcurrentMap<String, AtomicLongMap<String>> deviceErrorHolder = Maps.newConcurrentMap();

下面是我的方法,它以非常快的速度从多线程应用程序调用,所以我需要确保它很快。

  public void addDeviceErrorStats(String deviceName, String errorName) {
    AtomicLongMap<String> errorMap = deviceErrorHolder.get(deviceName);
    if (errorMap == null) {
      errorMap = AtomicLongMap.create();
      AtomicLongMap<String> currenttErrorMap = deviceErrorHolder.putIfAbsent(deviceName, errorMap);
      if (currenttErrorMap != null) {
        errorMap = currenttErrorMap;
      }
    }
    errorMap.incrementAndGet(errorName);
  }

对于每个 deviceName,我将有一个 AtomicLongMap,其中将包含不同 errorName 的所有计数。

  ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorA");
  ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorB");
  ExceptionCounter.getInstance().addDeviceErrorStats("deviceA", "errorC");

  ExceptionCounter.getInstance().addDeviceErrorStats("deviceB", "errorA");
  ExceptionCounter.getInstance().addDeviceErrorStats("deviceB", "errorB");

我的 addDeviceErrorStats 方法线程安全吗?还有我更新 deviceErrorHolder 地图值的方式是否正确?这意味着它将是一个原子操作吗?我需要同步创建新的 AtomicLongMap 实例吗?还是 CM 会帮我解决这个问题?

我正在与 Java7 合作。

我相信你的方法是正确的。假设我们有两个并发线程为同一个设备调用它

errorMap 已经存在的情况是微不足道的,因为两个线程将得到相同的结果并对其调用 incrementAndGet,这是原子的。

现在让我们考虑errorMap 不存在的情况。假设第一个线程到达 AtomicLongMap.create(),然后安排第二个线程。这样的线程也会创建自己的本地地图。 putIfAbsent() 是原子的,因此其中一个线程将 return null,而第二个线程将 return 第一个放置的映射。在后一种情况下,您将丢弃此线程实例化的地图,并使用 returned 代替。我觉得不错。

您可以使用 computeIfAbsent() 创建一个 lot 更简单的版本。

AtomicLongMap<String> errorMap = deviceErrorHolder.computeIfAbsent(deviceName, a -> AtomicLongMap.create());
errorMap.incrementAndGet(errorName);

computeIfAbsent(在并发映射中)特别用于执行空检查逻辑的原子版本。如果 deviceName 键有一个值,它是 returned,否则计算被原子地调用,计算的 return 值既与映射中的键相关联,也与returned.