Java Stream减少无法解释的行为

tan*_*khi 4 java reduce java-8 java-stream

任何人都可以指出正确的方向,因为我无法理解问题。

我正在执行以下方法。

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    List<String> join = vals.parallelStream().reduce(new ArrayList<String>(),
            (List<String> l, String v) -> {

                l.add(v);

                return l;
            }, (a, b) -> {                   
                a.addAll(b);
                return a;
            }

    );

   System.out.println(join);

}
Run Code Online (Sandbox Code Playgroud)

它打印

[null,a,null,a]

我不明白为什么它将两个空值放在结果列表中。我希望答案是

[a,b]

因为它是并行流,所以第一个要减少的参数

新的ArrayList()

每个输入值a和b可能会被调用两次。

然后,累加器函数可能会被调用两次,因为它是parallelStream,并在每次调用中传递每个输入“ a和b”以及由种子值提供的列表。因此,将a添加到列表1,将b添加到列表2(反之亦然)。之后,组合器将合并两个列表,但不会发生。

有趣的是,如果我在累加器中放入一条print语句以打印输入值,则输出会更改。所以下面

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    List<String> join = vals.parallelStream().reduce(new ArrayList<String>(),
            (List<String> l, String v) -> {
                System.out.printf("l is %s", l);
                l.add(v);
                System.out.printf("l is %s", l);
                return l;
            }, (a, b) -> {
                a.addAll(b);
                return a;
            }

    );

   System.out.println(join);

}
Run Code Online (Sandbox Code Playgroud)

结果输出

l是[] l是[b] l是[b,a] l是[b,a] [b,a,b,a]

谁能解释一下。

Mus*_*waz 5

使用Collections.synchronizedList()时应使用parallelStream()。因为ArrayList不是线程安全的,并且在同时访问它时会出现意外行为,就像您使用进行操作一样parallelStream()

我已经修改了您的代码,现在可以正常使用了:

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    // Use Synchronized List when with parallelStream()
    List<String> join = vals.parallelStream().reduce(Collections.synchronizedList(new ArrayList<>()),
            (l, v) -> {
                l.add(v);
                return l;
            }, (a, b) -> a // don't use addAll() here to multiplicate the output like [a, b, a, b]
    );
    System.out.println(join);
}
Run Code Online (Sandbox Code Playgroud)

输出:

有时您会得到以下输出:

[a, b]
Run Code Online (Sandbox Code Playgroud)

有时这个:

[b, a]
Run Code Online (Sandbox Code Playgroud)

这样做的原因是它是a,parallelStream()所以您不能确定执行顺序。