You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

并行流初始化ArrayList大小异常,串行流正常的原因咨询

为什么并行流操作ArrayList会导致大小不符?

这个问题其实踩中了Java集合类里一个经典的坑——ArrayList本身不是线程安全的,而并行流会让多个线程同时对它进行修改,这就引发了并发操作下的竞态条件,最终导致集合大小达不到预期。

我来拆解一下具体原因:

  • ArrayList的add方法没有同步保护:ArrayList的add()方法内部并没有加锁或者使用原子操作。当多个线程同时调用add()时,会出现多个线程同时读取当前的size值,然后尝试将元素放到对应的位置,最后再把size加1。这时候就可能出现两个线程都往同一个索引位置放元素,最终size只增加了1,相当于丢失了一个元素。这种情况发生的次数多了,最终集合的大小自然就会比指定的size小。

  • 并行流的多线程执行逻辑:当你调用parallel()后,IntStream会把遍历任务拆分到多个线程中并行执行,每个线程都在执行arrayList.add(defaultValue)。除了size更新的竞态条件,ArrayList的扩容逻辑也会因为并发操作出问题——比如一个线程正在扩容elementData数组,另一个线程还在往旧的数组里写数据,这部分数据就会被丢弃,同样导致元素丢失。

  • 单线程下的安全保障:当你去掉parallel()后,整个遍历是在单线程里顺序执行的,所有add()操作都是依次完成的,不存在多个线程同时修改ArrayList的情况,所以最终集合的大小完全符合预期。

怎么解决这个问题?

如果还是想用并行流来初始化集合,可以试试这些方案:

  1. 使用线程安全的集合类:比如CopyOnWriteArrayList,它的add方法是线程安全的,不过要注意它的写操作成本较高,适合读多写少的场景。

    private CopyOnWriteArrayList<Integer> createArrayList(int size, int defaultValue) {
        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
        IntStream.range(0, size).parallel().forEach(i -> list.add(defaultValue));
        return list;
    }
    
  2. 用并行流的collect方法收集:这是更推荐的方式,因为Collectors的实现会处理并发收集的问题,避免手动操作非线程安全集合的风险。如果需要返回ArrayList,可以指定集合类型:

    private ArrayList<Integer> createArrayList(int size, int defaultValue) {
        return IntStream.range(0, size)
                        .parallel()
                        .map(i -> defaultValue)
                        .collect(Collectors.toCollection(ArrayList::new));
    }
    
  3. 手动同步add操作:在add方法外面加同步锁,不过这样会让并行流失去并行的意义,线程都会阻塞等待锁,性能和单线程差不多,不推荐:

    private ArrayList<Integer> createArrayList(int size, int defaultValue) {
        ArrayList<Integer> arrayList = new ArrayList<>(size);
        Object lock = new Object();
        IntStream.range(0, size).parallel().forEach(i -> {
            synchronized (lock) {
                arrayList.add(defaultValue);
            }
        });
        return arrayList;
    }
    

内容的提问来源于stack exchange,提问作者yoni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:45:08