在处理Java 8流管道时,对顺序()和并行()的调用顺序是否重要?

时间:2017-02-24 19:05:52

标签: java parallel-processing java-stream

sequential()parallel()的调用放置是否会改变Java 8流的管道执行方式?

例如,假设我有这段代码:

new ArrayList().stream().parallel().filter(...).count();

在这个例子中,很明显filter()将并行运行。但是,如果我有这段代码怎么办:

new ArrayList().stream().filter(...).parallel().count();

filter()是否仍然并行运行或是否按顺序运行?之所以不清楚,是因为像filter()这样的中间操作是懒惰的,即在调用count()之类的终端操作之前它们不会运行。因此,在调用count()时,我们有一个并行流管道,但filter()按顺序执行,因为它在调用parallel()之前?< / p>

2 个答案:

答案 0 :(得分:8)

请注意the Stream’s class documentation的结尾:

  

流管道可以顺序执行,也可以并行执行。此执行模式是流的属性。通过初始选择的顺序或并行执行来创建流。 (例如,Collection.stream()创建一个顺序流,Collection.parallelStream()创建一个并行流。)这种执行模式的选择可以通过BaseStream.sequential()或BaseStream.parallel()方法修改,并且可以使用BaseStream.isParallel()方法查询。

换句话说,调用sequential()parallel()只会更改流的属性及其在终端操作开始时的状态决定整个管道的执行模式。

这可能没有在所有地方明确记录,因为,并非总是如此。在早期开发中,有些原型具有不同的阶段模式。 2013年3月This mail解释了这一变化。

答案 1 :(得分:3)

至少在标准的Oracle Java 8实现中,尽管parallel()方法被定义为&#34;中间操作&#34;,但它并不完全是懒惰的。也就是说,无论您是否进行终端操作,它都会立即生效。请考虑以下示例:

public class SimpleTest {

    public static void main(String[] args) {
        Stream<Integer> s = Stream.of(1,2,3,4,5,6,7,8,9,10);
        System.out.println(s.isParallel());
        Stream<Integer> s1 = s.parallel();
        System.out.println(s.isParallel());
        System.out.println(s == s1);
    }

}

我机器上的输出是:

false
true
true

它告诉我们parallel()会立即更改基础流的状态(并返回该流)。

但是,Javadoc是以允许这样的方式编写的,但不需要。这意味着其他流实现可以在parallel()操作之前以不同于其后的执行模式执行操作。

简而言之,无论如何,这都不是你可以依赖的行为。