java中parallelStream中的Bug

java中parallelStream中的Bug,java,filter,stream,reduce,parallelstream,Java,Filter,Stream,Reduce,Parallelstream,有人能告诉我为什么会发生这种情况,这是预期的行为还是一个bug吗 List<Integer> a = Arrays.asList(1,1,3,3); a.parallelStream().filter(Objects::nonNull) .filter(value -> value > 2) .reduce(1,Integer::sum) List a=Arrays.asList(1,1,3,3); a、 parallelStream

有人能告诉我为什么会发生这种情况,这是预期的行为还是一个bug吗

List<Integer> a = Arrays.asList(1,1,3,3);

a.parallelStream().filter(Objects::nonNull)
        .filter(value -> value > 2)
        .reduce(1,Integer::sum)

List a=Arrays.asList(1,1,3,3);
a、 parallelStream().filter(对象::非空)
.filter(值->值>2)
.reduce(1,整数::和)
回答:
10


但是如果我们使用
stream
而不是
parallelStream
,我得到了正确的预期的
答案7

减少的第一个参数称为“identity”,而不是“initialValue”

1
根据加法没有标识
1
是乘法的标识

但是,如果要对元素求和,则需要提供
0


Java使用“identity”而不是“initialValue”,因为这个小技巧允许轻松地并行化
reduce


在并行执行中,每个线程将在流的一部分上运行reduce,当线程完成时,它们将使用完全相同的reduce函数进行组合

虽然它看起来像这样:

mainThread:
  start thread1;
  start thread2;
  wait till both are finished;

thread1:
  return sum(1, 3); // your reduce function applied to a part of the stream

thread2:
  return sum(1, 3);

// when thread1 and thread2 are finished:
mainThread:
  return sum(sum(1, resultOfThread1), sum(1, resultOfThread2));
  = sum(sum(1, 4), sum(1, 4))
  = sum(5, 5)
  = 10

我希望您能看到,发生了什么以及为什么结果不是您期望的。

检查
reduce
:“…标识值必须是累加器函数的标识。这意味着对于所有
x
累加器。应用(标识,x)
等于
x
。”-不是
1
Integer::sum
能够使用并行流的情况,减少是分部分进行的,每个部分添加一个(可能每个元素一次)-使用
0
进行尝试,结果应该是正确的,但为什么流的结果不同?因为非并行流按顺序工作。我将在几分钟后的回答中提供一个示例Hanks@Benjamin这非常有帮助。有趣的是:算法有点不同-
identity
即使值被过滤掉也会被添加:
IntStream.range(01100).parallel().filter(v->v<0).reduce(1,Integer::sum)
36
使用jshell 1.15)@用户15244370是的。结果取决于使用的线程数。您的示例给出:
4
用于1个线程,
12
用于2个线程,
20
用于4个线程,
36
用于8个线程。我猜除了线程计数之外还有一个块大小,因此每个线程一次只计算N个元素,完成后将得到下一个N个元素。