Stream在顺序模式下工作,但在并行模式下工作

fas*_*sth 2 java parallel-processing lambda java-8 java-stream

目前我正在阅读Java 8 Lambdas:实用功能编程(非常有趣且写得很好的书,没有.).

在第6章之后有一个练习:

代码将列表中的每个数字相乘,并将结果乘以5.这样可以顺序执行,但在并行运行时会出错.

public static int multiplyThrough(List<Integer> linkedListOfNumbers) {
    return linkedListOfNumbers.parallelStream()
                       .reduce(5, (acc, x) -> x * acc);
}
Run Code Online (Sandbox Code Playgroud)

和解决方案:

public static int multiplyThrough(List<Integer> numbers) {
    return 5 * numbers.parallelStream()
                      .reduce(1, (acc, x) -> x * acc);
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么第一种方法在并行模式中是错误的,并且书中没有解释.

请解释.

JB *_*zet 6

javadoc说:

标识值必须是累加器函数的标识.这意味着对于所有t,accumulator.apply(identity,t)等于t.累加器函数必须是关联函数.

在您的第一个示例中显然不是这种情况:

5*x不等于x.

它在并行模式下没有给出相同结果的原因是,在这种模式下,流被分成块,并且对每个块应用减少,然后减少每个块的结果.因此,您最终会多次乘以5,而在顺序模式下,乘以5只会发生一次.

  • 您可以使用`reduce(acc).orElse(identity)`表单完全消除此要求.现在`identity`不需要是`acc`函数的标识值. (3认同)
  • 身份**任何数字*必须等于该数字.只适用1,0*5不是5. (2认同)