Pus*_*pak 1 java concurrency multithreading java.util.concurrent java-8
在多线程环境中,我正在 ConcurrentHashMap 实现上执行 get 和 put 操作。然而,结果却出乎意料。请找到下面的代码和输出。
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Test {
private static final List<String> bars = Arrays.asList("1","2","3","4","5","6","7","8","9","10");
private static final String KEY = UUID.randomUUID().toString();
private static ExecutorService executorService = null;
public static void main(String[] args) {
for (int i = 1; i <= 20; i++) {
executorService = Executors.newFixedThreadPool(2);
Map<String, AtomicInteger> map = new ConcurrentHashMap<>();
performMapOps(map);
executorService.shutdown();
try {
while (!executorService.awaitTermination(1, TimeUnit.SECONDS));
System.out.println(map.get(KEY));
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void performMapOps(Map<String, AtomicInteger> map) {
for (int i = 1; i <= bars.size(); i++) {
executorService.execute(() -> ops(map));
}
}
private static void ops(Map<String, AtomicInteger> map) {
if (!map.containsKey(KEY)) {
AtomicInteger atomicInteger = new AtomicInteger(1);
map.put(KEY, atomicInteger);
} else {
map.get(KEY).set(map.get(KEY).intValue() + 1);
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出 - 它应该始终是 10,但是对于上面的代码来说并非如此。请找到下面的输出。
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
9
10
10
Run Code Online (Sandbox Code Playgroud)
有时,它给我的值不是 10。请帮助理解,为什么会出现这种意外行为以及如何解决这个问题?
您的代码存在竞争条件。两个线程可以同时决定!map.containsKey(KEY)错误并将不同的值分配new AtomicInteger(1)给映射。
两个线程可以同时决定这!map.containsKey(KEY)是真的,并且它们都可以计算map.get(KEY)为相同的值,因此使用 存储相同的新值.set(map.get(KEY).intValue() + 1)。
Map.computeIfAbsent()更新的原子操作可以通过使用with来实现,AtomicInteger.incrementAndGet()以确保计数器递增一致,而无需另一个线程更新值:
private static void ops(Map<String, AtomicInteger> map) {
map.computeIfAbsent(KEY, k -> new AtomicInteger()).incrementAndGet();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
74 次 |
| 最近记录: |