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

执行Java parallel stream时list.size为何变化?相关疑问求证

关于Java并行Stream中list.size()变化的疑问解答

先看你给出的代码:

static void statefullParallelLambdaSet() {
    Set<Integer> s = new HashSet<>(
        Arrays.asList(1, 2, 3, 4, 5, 6)
    );
    
    List<Integer> list = new ArrayList<>();
    int sum = s.parallelStream().mapToInt(e -> {    // pipeline start
        if (list.size() <= 3) {     // list.size() changes while the pipeline operation is executing.
            list.add(e);            // mapToInt's lambda expression depends on this value, so it's stateful.
            return e;
        }
        else return 0;
    }).sum();   // terminal operation

    System.out.println(sum);
}

下面逐个解答你的疑问:

1. 为什么pipeline执行期间list.size()会变化?

代码里的lambda逻辑会直接修改共享的list:只要当前list.size() <=3,就执行list.add(e)。从Stream启动(调用parallelStream())到终端操作sum()执行完成的整个过程中,lambda会不断处理Set中的元素,只要满足条件就会给list添加元素,所以list.size()会从0开始动态增长,直到达到3后不再变化——整个pipeline执行过程中list的大小不是固定的,这就是注释想表达的意思。

2. 并行流中多线程同时执行list.add(e),是不是每次执行时list.size()都会变化?

这个说法不准确,而且这里存在严重的线程安全问题:

  • ArrayList本身不是线程安全的集合,多线程同时调用add()时,会出现并发修改异常、size计算错误(比如多个线程同时读取到size=2,都执行add,最终size可能只变成3而不是4)、元素覆盖等问题。
  • 就算不考虑线程安全问题,也不是每次执行lambda时size都会“正确”变化:多个线程可能同时读取到同一个size值,导致多次add操作只让size增加一次,所以实际size的变化是不可预测的,和代码逻辑预期的“每次add就+1”不一致。

3. 串行流时list.size()也变化,是不是因为Set无序导致的?

这个理解有误:

  • 串行流中list.size()变化是必然的——lambda逻辑本身会在size<=3时添加元素,所以size一定会从0逐步增加到3,之后不再变化,这个变化和Set是否无序无关。
  • Set无序影响的是哪些元素被添加到list中,进而影响最终的sum结果。比如第一次串行执行时可能取到1、2、3先被add,sum是6;第二次可能取到2、4、5先被add,sum是11。但不管元素顺序如何,list的size都会从0增长到3,这个变化过程是确定的,只是添加的元素不同而已。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:50:28