为什么并发放入 ConcurrentHashMap 不会产生预期结果?

tl2*_*221 0 java concurrency multithreading hashmap concurrenthashmap

我正在尝试使用多个线程测试并发放入ConcurrentHashMap,但处理后的地图大小不是我所期望的。

我有以下代码将 1000 个条目插入到 a 中ConcurrentHashMap

@Test
public void testThreadSafetyConcurrentHashMap() {
    Map<Integer, Integer> map = new ConcurrentHashMap<>();

    Runnable runnable = () -> {
        for (int i = 0; i < 1000; i++) {
            map.put(i, i);
        }
    };

    ExecutorService executorService = Executors.newFixedThreadPool(4);
    for (int i = 0; i < 4; i++) {
        executorService.submit(runnable);
    }

    System.out.println(map.size());
}
Run Code Online (Sandbox Code Playgroud)

我预计会map.size()收到 1000 件商品,但并不是每次都收到。

有人能告诉我问题是什么吗?我认为4个线程同时放入1000个项目,最终会导致总共1000个项目吗?

Ale*_*nko 6

您可以使用它ExecutorService.invokeAll()来确保在检查映射的大小之前所有线程都已完成其工作。

此方法返回“当全部完成时保持其状态和结果的 Future 列表”,即它是阻塞的,这就是我们在这种情况下需要的(我们对其返回值不感兴趣,并且在下面的代码中省略了它)。

invokeAll()需要一个集合Callable,我们可以用它来Executors.callable()将 a 转换Runnable为 a Callable

Map<Integer, Integer> map = new ConcurrentHashMap<>();
    
Runnable runnable = () -> {
    for (int i = 0; i < 1000; i++) {
        map.put(i, i);
    }
};
    
ExecutorService executorService = Executors.newFixedThreadPool(4);

executorService.invokeAll(Collections.nCopies(4, Executors.callable(runnable)));
    
System.out.println(map.size());
Run Code Online (Sandbox Code Playgroud)