为什么peek操作在Java并行流中不执行?
问题描述
运行以下代码后,输出始终是:
main sort3 main sort3 main sort3 main sort3
sorted之后的peek操作完全没执行,这是怎么回事?
代码片段:
public static void main(String[] args) throws InterruptedException { Random random = new Random(); Stream<Integer> parallel = Stream.generate(() -> random.nextInt(1000)) .limit(10) .sorted((a, b) -> { System.out.println(Thread.currentThread().getName() + " sort3 "); return a.compareTo(b); }) //3 .peek(i -> System.out.println(Thread.currentThread().getName() + " peek4 " + i)) //4 .peek(i-> System.out.println(Thread.currentThread().getName()+" peek5 " + i)) //5 .parallel().count(); Thread.sleep(20000); }
问题原因与解决
这是Java Stream的短路优化搞的鬼——你调用的count()方法只需要知道元素总数,完全不需要处理排序后的元素内容,所以框架直接跳过了sorted之后的peek操作。
具体来说:
sorted是有状态的中间操作,必须先收集全所有元素才能排序,所以你能看到sorted里的打印输出。- 但
count()只关心“有多少个元素”,不管元素是什么。当你把流转为并行流后,Stream的优化机制判定后续的peek对结果毫无影响,就直接跳过了这些步骤。
要让peek执行,就得换个需要消费元素内容的终端操作,比如forEach或者collect,别用只统计数量的count()。比如把最后一行改成:
.parallel().forEach(i -> {});
或者:
.parallel().collect(Collectors.toList());
顺带提一句:你把parallel()放在终端操作前其实不太合理,最好把并行流转换放在更早的位置(比如generate之后),这样中间操作也能并行执行,但这不是peek不执行的核心原因。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

