我需要从多线程应用程序填充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。
答案 0 :(得分:1)
您可以使用computeIfAbsent()
创建 lot 更简单的版本。
AtomicLongMap<String> errorMap = deviceErrorHolder.computeIfAbsent(deviceName, a -> AtomicLongMap.create());
errorMap.incrementAndGet(errorName);
computeIfAbsent
(在并发映射中)特别适用于执行空检查逻辑的原子版本。如果deviceName
键有值,则返回它,否则计算将以原子方式调用,并且计算的返回值既与地图中的键相关联又返回。
答案 1 :(得分:0)
我相信你的方法是正确的。假设我们有两个并发线程为同一个设备调用它
errorMap已经存在的情况很简单,因为两个线程都会相同并在其上调用incrementAndGet
,这是原子的。
现在让我们考虑一下errorMap不存在的情况。假设第一个线程到达AtomicLongMap.create()
,然后安排第二个线程。这样的线程也会创建自己的本地地图。 putIfAbsent()
是原子的,因此其中一个线程将返回null,而第二个将返回第一个放置的地图。在后一种情况下,您将丢弃由此线程实例化的地图,并使用返回的地图。对我来说很好看。