为何ConcurrentHashMap并发put后无法稳定得到预期的1000条记录?
问题分析与解决方案
问题根源
- 主线程未等待异步任务完成:你提交任务到线程池后,主线程没有等待所有线程执行完put操作就直接打印map的size。
ExecutorService.submit()是异步执行的,主线程执行System.out.println(map.size())时,可能还有线程在往map里写数据,此时拿到的是未完成状态的size,自然和预期不符。 - 这里的问题和ConcurrentHashMap的线程安全性无关,它的
put方法本身是线程安全的,相同键的并发put会保证最终值是最后一次写入的结果,但前提是你要等所有写入操作都完成再统计size。
修复后的代码
@Test public void testThreadSafetyConcurrentHashMap() throws InterruptedException { 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); } // 关闭线程池,不再接受新任务 executorService.shutdown(); // 等待所有任务执行完成,超时时间设置为10秒(可根据实际调整) if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { // 超时后强制关闭线程池 executorService.shutdownNow(); } System.out.println(map.size()); // 此时会稳定输出1000 }
补充说明
因为四个线程都是对0-999这1000个相同的键执行put操作,ConcurrentHashMap会保证相同键的put操作是原子性的,最终每个键只会保留一个条目,所以所有任务完成后,map的size必然是1000。
内容的提问来源于stack exchange,提问作者tl221
相关产品推荐
相关产品推荐

