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

我正在执行以下方法。

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);

}

它打印

[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);

}

结果输出

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

谁能解释一下。

最佳答案

使用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);
}

输出:

有时您会得到以下输出:
[a, b]

有时这个:
[b, a]

原因是它是一个parallelStream(),因此您不确定执行顺序。

10-05 23:03