这篇博客一起来研究下使用并行流。借组多核处理器并行执行代码可以显著提高性能,但是并行编程可能十分复杂且容易出错,流API提供的好处之一是能够轻松可靠的并行执行一些操作。请求并行处理流,首先要获得一个并行流。

获取一个并行流有2个方法:

1,Collection定义的parallelStream()方法

2,对顺序流调用parallel()方法。

一下代码演示如果获取一个并行流:

public static void main(String[] args) throws Exception
{
List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
//直接从集合中获取并行流
Stream<Integer> parallelStream = list.parallelStream();
//先获取一个顺序流,然后在顺序流的基础上获取一个并行流
Stream<Integer> stream = list.stream();
Stream<Integer> parallel = stream.parallel(); //Stream中有一个方法可以判断当前的流是不是并行流,一下代码输出全是true,也就是全部都是并行流
System.out.println(parallelStream.isParallel());
System.out.println(stream.isParallel());
System.out.println(parallel.isParallel());
}

获取并行流,有2点要注意,

1,对于并行流,只有在环境支持的情况下才可以实现并行处理

2,在一个顺序流的基础上调用parallel()方法,原来的顺序流也就变成了并行流了。如果调用该方法的流原来已经就是一个并行流了,那么就直接返回该调用流。

当然我们也可以将一个并行流转换成一个顺序流:在并行流上调用sequential()就可以啦。

public static void main(String[] args) throws Exception
{
List<Double> list = new ArrayList<>(4);
list.add(1.0);
list.add(2.0);
list.add(3.0);
list.add(4.0); //获取一个顺序流
Stream<Double> stream = list.stream();
System.out.println(stream.isParallel());
//顺序流上转换成一个并行流
Stream<Double> parallelStream = stream.parallel();
Stream<Double> unordered = parallelStream.unordered();//将流里面的元素设置无序
System.out.println(parallelStream.isParallel());
//并行流上转换成一个顺序流
Stream<Double> sequential = parallelStream.sequential();
System.out.println(sequential.isParallel());
}
  • 处理并行流

获得并行流后,如果环境支持并行处理,那么在该流上发生的操作就可以并行执行。区别于顺序流,并行流的相关操作发生在不同的线程上。一般来说,应用到并行流上的任何操作都必须是无状态的,不干预的,并且具有关联性的。这样子可以确保在并行流上执行操作得到的结果,和在顺序流上执行相同操作得到的结果相同。





上一篇博客中,我们整理到了缩减操作,reduce()方法的第3个方法,就是专门用来指定如何合并并行结果的。

reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)在这个版本中,第三个函数将第二个函数得到的2个值合并起来。





以下代码使用并行流,计算一个集合中元素的积:

public static void main(String[] args) throws Exception
{
List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
//直接从集合中获取并行流,然后执行缩减操作,下面的代码输出24
System.out.println(list.parallelStream().reduce(1, (a, b) -> a * b, (a, b) -> a * b));
}

处理并行流,有2点要注意:

1,在对并行流做缩减操作时,reduce()函数的第2个参数和第3个参数可以是做相同的操作,也可以是不同的操作,在有些情况下,这2个参数做的操作必须是不同的。来看下面这个例子:

public static void main(String[] args) throws Exception
{
List<Double> list = new ArrayList<>(4);
list.add(1.0);
list.add(2.0);
list.add(3.0);
list.add(4.0);
//直接从集合中获取并行流,然后执行缩减操作,下面的代码输出24
//下面的代码输出4.898979485566357,这里是顺序流
System.out.println(list.stream().reduce(1.0, (a, b) -> a * Math.sqrt(b)));
//下面的代码输出1.8612097182041991,这里是并行流,正确
System.out.println(list.parallelStream().reduce(1.0, (a, b) -> a * Math.sqrt(b), (a, b) -> a * b));
//下面的代码输出1.8612097182041991,这里是并行流,错误
System.out.println(list.parallelStream().reduce(1.0, (a, b) -> a * Math.sqrt(b), (a, b) -> a * Math.sqrt(b))); }

上面的代码中,累加器函数将2个元素的平方根相乘,但是合并器则将部分结果相乘,所以这2个函数是不同的,如果累加器函数和合并器函数是同一个函数,这将导致错误,因为当合并2个部分结果的时,相乘的是它们的平方根,而不是部分结果自身。值得注意的是,上面对reduce()方法的调用中,如果将流改成顺序流,操作将肯定得到正确的结果,所以我们在测试的时候也可以取值顺序流操作的结果来作为检验标准。





2,在使用并行操作时,关于流还有一点需要注意就是元素的位置。流可以时候有序的,也可以是无序的。一般来说,如果数据源是有序的,那么流也就是有序的。但是,在使用并行流的时候,有时候允许流是无序的这样子可以死获得性能上的提升。当并行流无序时,流的每个部分都可以被单独操作,而不是与其他部分协调。当操作的顺序不重要时,可以调用unordered()方法来指定无序行为。

其实有些api本身就是有序的或者说无序的,比如forEach()方法不一定保留并行流的顺序,但是在对并行流的每个元素执行操作时希望保留顺序的话,可以使用forEachOrdered()方法。

流API--使用并行流的更多相关文章

  1. Fork/Join框架与Java8 Stream API 之并行流的速度比较

    Fork/Join 框架有特定的ExecutorService和线程池构成.ExecutorService可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出 ...

  2. JAVA8给我带了什么——并行流和接口新功能

    流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...

  3. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  4. java8新特性——并行流与顺序流

    在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...

  5. 三、并行流与串行流 Fork/Join框架

    一.并行流概念: 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性的通过pa ...

  6. Java8新特性 - 并行流与串行流

    并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性地通过parallel()和 ...

  7. java8学习之收集器枚举特性深度解析与并行流原理

    首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...

  8. 【Java8新特性】关于并行流与串行流,你必须掌握这些!!

    写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...

  9. Stream并行流详解

    1.并行与并发的区别 在说到并行的时候,相信很多人都会想到并发的概念.那么并行和并发两者一字之差,有什么区别呢? 并行:多个任务在同一时间点发生,并由不同的cpu进行处理,不互相抢占资源 并行: 并发 ...

随机推荐

  1. [笔记]《JavaScript高级程序设计》- JavaScript简介

    JavaScript实现 虽然JavaScript和ECMAScript通常都被人们用来表达相同的含义,但JavaScript的含义却比ECMA-262中规定的要多得多.一个完整的JavaScript ...

  2. left join,right join,inner join

    数据库中left join,right join,inner join的差异 具体详细说明 总的来说: JOIN:                                           ...

  3. mysql foreign key(外键) 说明与实例

    一,什么是foreign key,及其完整性 个人觉得,foreign key就是表与表之间的某种约定的关系,由于这种关系的存在,我们能够让表与表之间的数据,更加的完整,关连性更强.关于完整性,关连性 ...

  4. C# 生成二维码 QRCoder

    最近项目上有个需求,需要将某个文件的下载地址生成二维码,并展示到网页上. 目前网上生成二维码的方法有好几种,本文将介绍[QRCoder]生成二维码的方式 一.首先通过VS中的[NUGET]下载并引用Q ...

  5. 新浪新闻页面抓取(JAVA-Jsoup)

    1.使用gradle建立工程: 工程格式如下: include ':spider-demo' rootProject.name = 'my-spider-demo' settings def void ...

  6. python对pywifi模块的认识

    pywifi是一个用来搞wifi的模块 下一章我们将用他破解wifi密码 pywifi安装 pip install pywifi 下列代码判断是否有无限网卡 import pywifi import ...

  7. hackerrank [Week of Code 33] Bonnie and Clyde

    任意门 题意:给一个图,每次询问给三个点a,b,c,问是否存在一条从a到c,一条b到c的路径除c外无交点. 双连通分量缩点建出圆方树是必须的,然后我们需要判断c是否在a到b的路径上,或者c的某个相邻的 ...

  8. 51nod 1575 Gcd and Lcm

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1575 万年巨坑终于填掉了…… 首先是煞笔西瓜的做题历程O_O. ...

  9. bzoj:1661 [Usaco2006 Nov]Big Square 巨大正方形

    Description 农民 John 的牛参加了一次和农民 Bob 的牛的竞赛.他们在区域中画了一个N*N 的正方形点阵,两个农场的牛各自占据了一些点.当然不能有两头牛处于同一个点.农场的目标是用自 ...

  10. HDU-5421Victor and String

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5421 因为要在前面插字符,所以维护一个前缀链和后缀链,在同一棵回文树上搞,如果有某个最长回文后缀(或前缀) ...