【问题标题】:How to atomically update the value of ConcurrentMap in multithreaded application?如何在多线程应用程序中原子更新 ConcurrentMap 的值?
【发布时间】:2016-12-14 06:17:03
【问题描述】:

我有一个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。

【问题讨论】:

  • 你为什么不写一些测试用例来生成你的场景并分享结果:D
  • 您需要 computeIfAbsent 才能使其线程安全。
  • 我还在使用 Java 7,所以不能使用 computeIfAbsent
  • @PeterLawrey 那我的代码有问题吗?而且它不是线程安全的?
  • @user5447339 computeIfAbsent 将是一个单行,而 currentErrorMap 是最新创建的。

标签: java multithreading thread-safety concurrenthashmap atomic


【解决方案1】:

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

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

computeIfAbsent(在并发映射中)特别适用于执行您的空检查逻辑所做的原子版本。如果deviceName键有值,则返回,否则原子调用计算,计算的返回值与map中的键相关联并返回。

【讨论】:

  • 我的代码有什么问题?如果有问题,那么在 Java 7 中最好的方法是什么?
  • 啊,太糟糕了。猜猜您将不得不容忍您的版本具有的额外代码和一些不必要的对象创建。
  • 所以我的代码还可以吗?正如彼得提到的那样,Bcoz 可能不是线程安全的?
  • 是的,它只是有可能为每个deviceName 创建一个额外的对象。它没有数据丢失的可能性或其他问题。
  • 好吧..我在想这个,你认为如果我使用番石榴中的LoadingCache 那么它可以减少这个额外的对象创建吗? bcoz 它可以自动同步创建新的 AtomicLongMap 实例吗?是的,我不会使用所有的缓存功能。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    相关资源
    最近更新 更多