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

并行流Stream#reduce中Accumulator为何仅以identity作为初始调用参数?

问题描述

我使用三参数版本的Stream#reduce方法,以字符串列表为处理对象、0作为identity,Accumulator负责累加identity与字符串长度,Combiner负责合并两个部分结果。代码如下:

List<String> strings = new ArrayList<>();
IntStream.range(0, 10)
            .forEach(i -> strings.add("a"));

System.out.println(strings.stream()
    .parallel()
    .reduce(0,
            (res, s) -> {
                System.out.println("Accumulator called with " + res + " and " + s);
                return res + s.length();
            },
            (a, b) -> {
                System.out.println("Combiner called with " + a + " and " + b);
                return a + b;
            }));

运行该代码后,控制台十次打印Accumulator called with 0 and a,而部分结果的求和仅在Combiner中进行,例如打印Combiner called with 1 and 1、Combiner called with 5 and 5等。为何Accumulator不会以之前的非identity结果与字符串调用,即为何看不到Accumulator called with 1 and a这类打印信息?

问题解析

这是因为并行流采用分片独立计算再合并结果的处理逻辑:

  • 并行流会把原始的10个元素拆分成多个独立子任务(具体分片数量由JVM根据运行环境决定,比如分成5组每组2个,或2组每组5个)。
  • 每个子任务都会从指定的identity(也就是0)开始,用Accumulator处理自己分片内的每个元素。所以每个子任务里的Accumulator每次都是拿0和当前元素计算,得到的子结果是该分片内所有元素长度的总和(比如一个分片有2个"a",就会两次调用Accumulator:0+1、0+1,得到两个1,之后由Combiner把这两个1合并成2)。
  • 所有子任务计算完成后,Combiner会把各个子结果逐步合并,最终得到总结果。

简单来说,并行流不是在单线程里连续累加(那样才会出现1 and a的情况),而是把任务拆成多个独立小任务,每个小任务都从零开始计算自己的部分,最后再把这些部分结果加起来,所以你看不到Accumulator用非identity的中间结果去处理下一个元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:15:37