forEach 和 forEachOrdered在Java 8 Stream的区别

默认分类·java筑基 · 2020-05-20 · 310 人浏览

Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));

Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s);

第二行输出的一直是: 
AAA 
BBB 
CCC 
而第一种输出的情况不确定。应为是并行处理。 
其实两者完成的功能类似,主要区别在并行处理上,forEach是并行处理的,forEachOrder是按顺序处理的,显然前者速度更快。

parallel()

采用并行化来处理stream流;当普通stream流时,即:

Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));

Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s);

forEachforEachOrdered没有区别

对于forEach ,当stream 为parallel的时候,是多个线程,并行处理的。因此输出的数据顺序不能保证。
由于是并行处理,数据处理效率较高。 

但是,对于操作共享变量的时候,需要注意安全问题,需要保证同步。


比如下面例子:


IntStream.range(0,1000).parallel().forEach(i->list.add(i)); 
System.out.println(list.size());

有可能会报错:Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException

或者会出现,list.size 不为1000

所以需要加同步锁来解决安全问题:

IntStream.range(0,1000).parallel().forEach(i->{lock.lock();
    try {    
        list.add(i);    
    }finally {        
        lock.unlock();   
     }
}); 
System.out.println(list.size());


对于forEachOrdeed ,当stream 为parallel的时候,尽管是多个线程,并行处理的。但是还是会按照他source原有的顺序输出,,底层是通过happensbefore原则保证了它的内存可见性。(可以理解为相当于用volatile修饰了吧)

所以下面的代码并不会报错:

IntStream.range(0,1000).parallel().forEachOrdered(i->list.add(i));
System.out.println(list.size());



stream java8