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

陌路散爱 提交于 2019-12-12 04:22:47

问题


I have a ConcurrentMap which I need to populate from multithread application. My map is shown below:

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

Below is my method which is called from multithreaded application at very fast rate so I need to make sure it is fast.

  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);
  }

For each deviceName, I will have an AtomicLongMap which will contain all the counts for different 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");

Is my addDeviceErrorStats method thread safe? And also the way I am updating the value of my deviceErrorHolder map is correct? Meaning will it be an atomic operation? Do I need to synchronize creation of new AtomicLongMap instances? Or CM will take care that for me?

I am working with Java7.


回答1:


You can create a lot simpler version of this with computeIfAbsent().

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

The computeIfAbsent (in concurrent maps) is especially meant to do an atomic version of what your null checking logic does. If the deviceName key has a value, it's returned, otherwise the computation is called atomically, and the return value of the computation is both associated with the key in the map as well as returned.




回答2:


I believe your method is correct. Let's assume we have two concurrent threads calling it for the same device

The case where the errorMap already existed is trivial, as both threads will get the same and call incrementAndGet on it, which is atomic.

Let's now consider the case where errorMap didn't exist. say the first thread gets to AtomicLongMap.create(), and then the second thread is scheduled. Such thread will also create its own local map. putIfAbsent() is atomic, hence one of the threads will return null, while the second will return the map put by the first. In the latter case, you're throwing away the map that was instantiated by this thread, and using the one returned instead. Looks good to me.



来源:https://stackoverflow.com/questions/41135998/how-to-atomically-update-the-value-of-concurrentmap-in-multithreaded-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!