我可以将 ConcurrentHashMap with Integer 用于线程安全计数器吗?



我想有几个计数器,我可以按名称寻址。所以,我可以这样实现它:

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.computeIfAbsent("key", k -> new Integer(0));
map.computeIfPresent("key", (k, v) -> v + 1);

它是线程代码安全的吗?

我想是的,因为我们因为ConcurrentHashMap而同步访问,并且设置新引用也是线程安全操作。由于安全发布,其他线程将看到这种情况发生变化,当我们在ConcurrentHashMap中保留存储桶锁定时会发生这种情况。

是的,它是线程安全的,你可以测试:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadsafeExample {
public static void main(String[] args) throws Exception {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
int count = 1000;
AtomicInteger doneTasks = new AtomicInteger();
Thread[] threads = new Thread[count];
for(int i = 0 ; i < threads.length ; ++i) {
threads[i] = new Thread(() -> {
map.computeIfAbsent("key", k -> new Integer(0));
map.computeIfPresent("key", (k, v) -> v + 1);
doneTasks.incrementAndGet();
});
}
for(int i = 0 ; i < threads.length ; ++i)
threads[i].start();
while (doneTasks.get() < count)
Thread.sleep(3);
System.out.println("we expected count of key is: " + count + ", and we get: " + map.get("key"));
}
}

输出:

we expected count of key is: 1000, and we get: 1000

您可以替换:

map.computeIfAbsent("key", k -> new Integer(0));
map.computeIfPresent("key", (k, v) -> v + 1);

map.compute("key", (k, v) -> v == null ? 1 : v + 1);

假设第一个语句map.computeIfAbsent("key", k -> new Integer(0));发生在"初始化时",然后有一堆线程执行map.computeIfPresent("key", (k, v) -> v + 1);形式的调用,是的,算法是正确的(我是否很好地理解了您的意图?

最新版本的 JDK 保证对ConcurrentHashMap.computeIfPresent()的调用不仅会调用以线程安全方式传入的表达式,它还会保证如果其他线程尝试同时对同一个键进行操作,它们将阻塞并排队,以便所有突变按顺序发生(这在分布式系统术语中称为可序列化性(。

最新更新