为什么顺序流和并行流的还原结果不同



我有以下列表integers(所有数字从0到999,999(:

List<Integer> integers = new ArrayList<>();
for (int i = 0; i != 10_000_000; ++i) {
    integers.add(i);
}

我正在尝试将以下内容作为Java 8流运行:

int sum = 0;
for (Integer i : integers) {
    sum = i % 2 == 0 ? i - sum : i + sum;
}
System.out.println(sum);

我期望以下输出:

0 - 0 = 0  
1 + 0 = 1  
2 - 1 = 1   
3 + 1 = 4  
4 - 4 = 0  
5 + 0 = 5  
6 - 5 = 1  
7 + 1 = 8
8 - 8 = 0   
...
999,998 - 999,997 = 1
999,999 + 1 = 10,000,000

10,000,000(顺便说一句,有人可以用数学来表达这一点吗?我不能...

如果我运行这个:

int sum = integers.stream().reduce(
                0,
                (sum, i) -> i % 2 == 0 ? i - sum : i + sum
            );

sum是预期金额,10,000,000 .

但是,如果我将流更改为并行流:

int sum = integers.parallelStream().reduce(
                0,
                (sum, i) -> i % 2 == 0 ? i - sum : i + sum
            );

sum 0

我似乎想不通为什么会这样,有人可以解释一下吗?

> Javadoc for reduce

使用关联累积函数对此流的元素执行缩减,

请注意"关联"一词:这是您的约简函数不具备的属性。

关联性

是并行化的关键:操作的应用顺序没有定义,如果没有关联性,结果在重新排序下不会是不变的。

如果你有两个以上的availableProcessors,你可以使用以下代码来说服自己答案取决于子任务的数量(注意,你不应该使用 10_000_000 作为问题大小,因为它在因式分解中必须有很多 2;使用 10_000_001(:

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "2");
System.out.println(IntStream.range(0,10_000_001).parallel().reduce(0,
    (sum, i) -> i % 2 == 0 ? i - sum : i + sum
));
更改

系统属性的值时,结果也会更改。

最新更新