如何更新 ConcurrentHashMap 线程安全中的值
How to update a Value in a ConcurrentHashMap threadsafe
我需要更新 ConcurrentHashmap 中的一个值,但我不确定如何确保线程安全。
Hashmap 是一个 ConcurrentHashMap,我需要获取自定义的实例 class,对其执行一些操作,然后将更新后的值放回。
有什么方法可以将这个 get-alter-put 操作组合成原子操作吗?
提前致谢
ConcurrentHashMap的computeIfPresent
方法是一种可能。来自 javadocs:如果存在指定键的值,则尝试在给定键及其当前映射值的情况下计算新映射。整个方法调用以原子方式执行(期望计算应该简短)。
一般来说,该方法是如何工作的?一些示例代码:
考虑具有键和值的 Map<String, Integer>
map
:{four=4, one=1, ten=10, two=2, three=3, five=5, eleven=11}
(1) 用新值更新映射(注意 lambda 是 BiFunction 返回新计算的值):
map.computeIfPresent("ten", (k, v) -> new Integer(100));
(2)函数returns为null,现有映射被移除:
map.computeIfPresent("eleven", (k, v) -> null);
(3) 不添加映射,因为不存在映射:
map.computeIfPresent("twenty", (k, v) -> new Integer(20));
编辑:
关于 compute()
的注意事项:使用相同的输入 map
数据(和方法参数),compute
方法的工作方式类似,但对于情况 3。请注意情况 3,其中 new可以添加映射:
(3) 添加了一个 new 映射。
您可以使用 ConcurrentHashMaps computeIfPresent https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfPresent-K-java.util.function.BiFunction-
但是由于 computeIfPresent 是一个代价高昂的操作,因为它是原子操作,并且在 BiFunction 的计算过程中,一些更新操作将被其他线程阻塞。您可以通过对并发 hashmap 的读取操作来排除这种情况,这非常快,如果 returns 不是 null ,则调用 computeIfPrsent
下面的代码获取键“1”的值并将其加 100 并以原子方式放回地图
ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
map.put(1,100);
Integer value = map.get(1);
if (value != null)
map.computeIfPresent(1, (key, oldValue) -> oldValue + 100);
}
我会说你可以使用
map.compute(key, (k,v) -> {
if(k != null) {
return v+1;
} else {
return some_var;
}
});
我需要更新 ConcurrentHashmap 中的一个值,但我不确定如何确保线程安全。
Hashmap 是一个 ConcurrentHashMap,我需要获取自定义的实例 class,对其执行一些操作,然后将更新后的值放回。
有什么方法可以将这个 get-alter-put 操作组合成原子操作吗?
提前致谢
ConcurrentHashMap的computeIfPresent
方法是一种可能。来自 javadocs:如果存在指定键的值,则尝试在给定键及其当前映射值的情况下计算新映射。整个方法调用以原子方式执行(期望计算应该简短)。
一般来说,该方法是如何工作的?一些示例代码:
考虑具有键和值的 Map<String, Integer>
map
:{four=4, one=1, ten=10, two=2, three=3, five=5, eleven=11}
(1) 用新值更新映射(注意 lambda 是 BiFunction 返回新计算的值):
map.computeIfPresent("ten", (k, v) -> new Integer(100));
(2)函数returns为null,现有映射被移除:
map.computeIfPresent("eleven", (k, v) -> null);
(3) 不添加映射,因为不存在映射:
map.computeIfPresent("twenty", (k, v) -> new Integer(20));
编辑:
关于 compute()
的注意事项:使用相同的输入 map
数据(和方法参数),compute
方法的工作方式类似,但对于情况 3。请注意情况 3,其中 new可以添加映射:
(3) 添加了一个 new 映射。
您可以使用 ConcurrentHashMaps computeIfPresent https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfPresent-K-java.util.function.BiFunction-
但是由于 computeIfPresent 是一个代价高昂的操作,因为它是原子操作,并且在 BiFunction 的计算过程中,一些更新操作将被其他线程阻塞。您可以通过对并发 hashmap 的读取操作来排除这种情况,这非常快,如果 returns 不是 null ,则调用 computeIfPrsent
下面的代码获取键“1”的值并将其加 100 并以原子方式放回地图
ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
map.put(1,100);
Integer value = map.get(1);
if (value != null)
map.computeIfPresent(1, (key, oldValue) -> oldValue + 100);
}
我会说你可以使用
map.compute(key, (k,v) -> {
if(k != null) {
return v+1;
} else {
return some_var;
}
});