谁能给我指出正确的方向,因为我无法理解这个问题。
我正在执行以下方法。
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]
我不明白为什么它会在结果列表中放置两个 null。我希望答案是
[a, b]
因为是并行流所以第一个参数要减少
new ArrayList()
可能会为每个输入值 a 和 b 调用两次。
然后累加器函数可能会被调用两次,因为它是一个 parallelStream 并在每次调用中传递每个输入“a 和 b”以及种子值提供的列表。所以 a 被添加到列表 1,b 被添加到列表 2(反之亦然)。之后,组合器将合并两个列表,但并没有发生。
有趣的是,如果我在累加器中放置一个打印语句来打印输入值,输出就会改变。所以下面
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 is []l is [b]l is [b, a]l is [b, a][b, a, b, a]
谁能解释一下。
最佳答案
在使用 parallelStream()
时,您应该使用 Collections.synchronizedList()
。因为 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()
,因此您无法确定执行顺序。
关于Java Stream 减少无法解释的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58006434/