跟我学 Java 8 新特性之 Stream 流(四)并行流

转载自   跟我学 Java 8 新特性之 Stream 流(四)并行流

随着对流API认识的慢慢深入,本章我们要讨论的知识点是流API里面的并行流了。

在开始讨论并行流之前,我先引发一下大家的思考,就你看到这篇文章的时间,你们是不是经常听到,Intel i7 CPU什么8核16线程,什么Android手机8核4GB这种消息,既然我们是处于一个多核处理器的时代,你们有没有想过并行地操作数组和集合框架,从而高速地执行我们对数组或者集合的一些操作呢?

或许你有想过这个问题,但是因为并行编程比较复杂,所以这些想法还停留在你的脑海当中,又或者你已经在路上了,反正你们就是最棒的(我他妈都这么夸你们了,就不能点个喜欢?)。

不管如何,在你看到这一篇文章的时候,我将带你走向并行地操作数组或者集合,当然是使用我们的并行流知识啦。

并行流

并行编程可谓是十分复杂并且很容易出错的,这估计就是我们绝大部分人的拦脚石。刚好Stream流库给我们解决了这个问题,在流API库里面提供了轻松可靠的并行操作。要想并行处理流相当简单,只需要使用一个并行流就可以了。

如第二篇文章中提到的那样,我们获取一个并行流是非常简单的,只需要对流调用一下parallel()就可以获取到一个并行流了(什么你居然不知道?那么多人看了我的文章,估计你要被他们甩开几条街了,赶紧回去看吧。),第二种方式就更加简单了,我们可以使用Collection接口提供给我们parallelStream(),也是可以获取到一个并行流的。

当然,并行操作肯定是需要环境支持的,你搞了一台一核一线程的小霸王,来跑我的高大上并行流,我也只能慢慢来了。如果你不是小霸王,那我们可以开始这节课的实战了,先拿上一篇的例子来改一下先,如果你不认真观察,你都找不出他们的不同之处:

public class Main {public static void main(String[] args) {learnStream();}private static void learnStream() {List<Integer> lists = new ArrayList<>();lists.add(1);lists.add(2);lists.add(3);lists.add(4);lists.add(5);lists.add(6);Optional<Integer> sum = lists.parallelStream().reduce((a, b) -> a + b);//这里把stream()换成了parallelStream()if (sum.isPresent()) System.out.println("list的总和为:" + sum.get());//21//<====> lists.stream().reduce((a, b) -> a + b).ifPresent(System.out::println);Integer sum2 = lists.stream().reduce(0, (a, b) -> a + b);//21System.out.println("list的总和为:" + sum2);Optional<Integer> product = lists.stream().reduce((a, b) -> a * b);if (product.isPresent()) System.out.println("list的积为:" + product.get());//720Integer product2 = lists.parallelStream().reduce(1, (a, b) -> a * b);//这里把stream()换成了parallelStream()System.out.println("list的积为:" + product2);//720}
}

得到结果和上一篇文章的一模一样。但是因为乘法和加法操作是可以发生在不同的线程里面的,因此这两个例子,在数据源足够大的时候,他们的运行的时间,差别相当地大了啊。

一般来说,应用到并行流的任何操作都必须是符合缩减操作的三个约束条件,无状态,不干预,关联性!因为这三大约束确保在并行流上执行操作的结果和在顺序流上执行的结果是相同的。

我们在上一篇讲缩减操作的时候,提到了三个reduce(),但是我们只讲了两个,我就不和你们皮了,直接开讲剩下的那一个,在并行流里面,你们会发现这个版本的reduce()才是真爱啊!

public interface Stream<T> extends BaseStream<T, Stream<T>> {
//、、、忽略其他无关紧要的元素
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
}在reduce()的这个版本当中,accumulator被称为累加器,combiner被称为合成器,combiner定义的函数将accumulator提到的两个值合并起来,因此,我们可以把上面的那个例子改成:private static void reduce3th() {List<Integer> lists = new ArrayList<>();lists.add(1);lists.add(2);lists.add(3);lists.add(4);lists.add(5);lists.add(6);Integer product2 = lists.parallelStream().reduce(1, (a, b) -> a * b,(a, b) -> a * b);System.out.println("list的积为:" + product2);//720}

他们得到的结果还是一样的。

你们可能以为accumulator和combiner执行的操作是相同的,但其实他们是可以不同的,下面的例子,你们要认真看了:假设List里面有三个Integer类型的元素分别为1,2,3。

现在的需求是分别让List里面的每个元素都放大两倍后,再求积。这个需求的正确答案应该是48;

 private static void reduce3th() {List<Integer> lists = new ArrayList<>();lists.add(1);lists.add(2);lists.add(3);Integer product = lists.parallelStream().reduce(1, (a, b) -> a *  (b * 2),(a, b) -> a * b);System.out.println("product:" + product);//48}

累加器部分是将两个元素分别放大两倍后,再相乘,合并器,是将两个部分相乘!如果能理解这里,恭喜你,你的技能有相当大的长进了!估计Stream流你就可以无往而不利了。

如果你还不能理解,就应该继续往下看了,跟着我的步伐慢慢走:

  1.    累加器部分(水平向右)

  2.        accumulator

  3. -----------------------------›

  4. thread-1:   1 * 1 * 2   =   2    |    合并器方向(竖直向下)

  5. thread-2:   1 * 2 * 2   =   4    |         combiner

  6. thread-3:   1 * 3 * 2   =   6    |   因此最终的答案是2  *  4  *  6  =   48(没毛病)

  7.                                 ˇ

  8. 注:水平方向最前面的1就是identity的值

此时,accumulator和combiner执行的操作是不是一定不能相同了。理解这些,对于理解并行流是非常重要的。

如果此时的combiner还是和accumulator相同,那么结果是什么样的呢:请看:

 private static void reduce3th() {List<Integer> lists = new ArrayList<>();lists.add(1);lists.add(2);lists.add(3);Integer product = lists.parallelStream().reduce(1, (a, b) -> a *  (b * 2),(a, b) -> a * b * 2 );System.out.println("product:" + product);//192}

192这个答案是怎么来的?

  1.    累加器部分(水平向右)

  2.        accumulator

  3. -----------------------------›

  4. thread-1:   1 * 1 * 2   =   2          |    合并器方向(竖直向下)

  5. thread-2:   1 * 2 * 2   =   4  *  2    |         combiner

  6. thread-3:   1 * 3 * 2   =   6  *  2    |   因此最终的答案是2  *  ( 4  *  2 ) *  (6  *  2)  =   192(没毛病)

  7.                                       ˇ

  8. 注:水平方向最前面的1就是identity的值

顺序流&并行流&无序流之间的切换操作

对于这三种流的切换,在BaseStream接口中提供了相应的方法,如果你还没有记住,回头再看一下第二篇文章吧。

关于使用并行流的时候,还有一个点需要记住:如果集合中或者数组中的元素是有序的,那么对应的流也是有序的。但是在使用并行流时,有时候流是无序的就能获得性能上的提升。因为如果流是无序的,那么流的每个部分都可以被单独的操作,而不需要与其他部分协调,从而提升性能。(又是无状态,说好的退休了呢)。所以当流操作的顺序不重要的时候,可以通过BaseStream接口提供的unordered()方法把流转换成一个无序流之后,再进行各种操作。

另外一点:forEach()方法不一定会保留并行流的顺序,如果在对并行流的每个元素执行操作时,也希望保留顺序,那么可以使用forEachOrdered()方法,它的用法和forEach()是一样的。因为在发布第一篇文章的时候,大家对forEach的反应比较大,很多人其实对forEach都有想法:比如调试难,等等。借这个机会,我谈一谈我对for&forEach的看法。

我们在访问一个数组元素的时候,最快的方式肯定是通过索引去访问的吧,而for循环遍历的时候就是通过下标进行的,所以效率那是相当的高,但是当我们的数据结构不是数组的时候,比如是链表的时候,可想而知,for循环的效率是有多低,但是forEach底层采用的是迭代器的方式,他对数据结构是没有要求的,不管上层的数据结构是什么,他都能保证高效地执行!

因此我的最终答案:如果数据结构是ArrayList这种数据结构,那你可以采用for,但是你的数据结构如果是LinkList那你千万别再用for,应该果断采用forEach,因为数据一多起来的,for此时的效率低得可怜,说不定你的机器就瘫痪了。这也是优化的一个小技巧吧,希望能帮助大家。

小结一下

并行流学会了,你的功力,真的就增长了。效率再也不是问题了,基本上关于并行流的方方面面,这篇文章都已经说提到了,但是Stream在JDK中的变化还是挺快的,我一旦发现有什么改动,会最快地更新这篇文章。下一篇我们继续探索新知识点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

运算和统计

一、变量&#xff1a; 1.是一种内容不固定的项&#xff0c;数据内容会因程序的运行而改变。 2.将变量存在计算机内存中&#xff0c;便于程序调用 3.变量有变量类型、变量名和值。 二、变量的类型&#xff1a; 1.字符串类型&#xff1a;存储姓名&#xff0c;性别&#xff0c;一句…

JS浏览器加载一个页面的过程

加载过程->从上向下逐行进行加载 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript">/** 浏览器在加载一个页面时&#xff0c;是按照自上向下的顺序加载的&…

MyBatis第四天(多表查询)

地址&#xff1a;引用MyBatis第四天&#xff08;多表查询&#xff09;

统一的.NET文档体验发布

Microsoft发布了新的.NET API阅读器。该阅读器可以查找所有相关的.NET文档。第一版中包括了.NET Framework、.NET Core、.NET Standard、Xamarin和Azure NuGet软件包的参考文档&#xff0c;并可根据用户反馈添加其它领域的文档。 该阅读器提供了在同一处搜索、展示、发现和浏览…

深入C#数据类型

一、类&#xff1a; 一组相同属性和方法的对象的集合 二、对象&#xff1a; 用来描述客观事物的实体 三、类和对象的关系&#xff1a; 抽象和具体的关系 四、封装&#xff1a; 隐藏内部细节&#xff0c;对外提供公共的接口&#xff0c;又称为信息隐藏。 五、封装的好处&#xf…

跟我学 Java 8 新特性之 Stream 流(三)缩减操作

转载自 跟我学 Java 8 新特性之 Stream 流&#xff08;三&#xff09;缩减操作 和前面两篇文章一起服用&#xff0c;效果会更佳。通过对流API的基础体验Demo和关键知识点的讲解&#xff0c;相信大家对流API都有一定的认识了&#xff0c;但是流API强大的功能&#xff0c;可不…

JS中字符串的常用方法

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript">//创建一个字符串var str "Hello Atguigu";/** 在底层字符串是以字符数组的形式保存的* ["…

使用Angular 4、Bootstrap 4、TypeScript和ASP.NET Core开发的Apworks框架案例应用

最近我为我自己的应用开发框架Apworks设计了一套案例应用程序&#xff0c;并以Apache 2.0开源&#xff0c;开源地址是&#xff1a;https://github.com/daxnet/apworks-examples&#xff0c;目的是为了让大家更为方便地学习和使用.NET Core、最新的前端开发框架Angular&#xff…

C#使用集合组织相关数据

一、为什么使用集合&#xff1f; 数组的长度是固定的&#xff0c;对数组中的元素进行动态添加和删除的时候很麻烦。集合可以更好的进行对元素添加和删除 二、ArrayList集合&#xff1a; 1.类似于数组&#xff0c;但是可以直观的动态维护。 2.位于System.Collections命名空间里面…

IntelliJ IDEA 最常用配置详细图解,新手入门必看

转载自 IntelliJ IDEA 最常用配置详细图解&#xff0c;新手入门必看 刚刚使用IntelliJ IDEA 编辑器的时候&#xff0c;会有很多设置&#xff0c;会方便以后的开发&#xff0c;磨刀不误砍柴工。 比如&#xff1a;设置文件字体大小&#xff0c;代码自动完成提示&#xff0c;版…

MyBatis(延迟加载 缓存)

mybatis目录 一对一延迟加载 1.在SqlMapConfig.xml中配置setting标签 2.在IAccoutDao.xml中配置association标签 3.测试类 4.成功运行 一对多延迟加载 2.在IUserDao.xml中配置collection标签 缓存 一级缓存 二级缓存 1.SqlMaoConfig.xml中 2.在需要使用二级缓存的实体类的mapp…

JS函数中的arguments

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript">/** 在调用函数时&#xff0c;浏览器每次都会传递进两个隐含的参数&#xff1a;* 1.函数的上下文对象 this…

剑英的区块链学习手记(二)

孙子说&#xff0c;知己知彼&#xff0c;百战不殆。 咱是通过小蚁学习区块链技术的。 开工之前&#xff0c;先了解一下小蚁的资料家族。 小蚁网站 https://www.antshares.org/ 小蚁源码 https://github.com/AntShares 小蚁SDK源码 https://github.com/ANTSHARESSdk 比较集…

PhotoShop基础知识

一、PhotoShop&#xff1a; 1.是由Adobe Systems开发和发行的专门用于图形图像处理的软件 2.优点&#xff1a;绘制或者处理后的图像&#xff0c;颜色鲜明、形象生动&#xff0c;能够给观者很好的视觉效果。 二、PhotoShop软件应用领域&#xff1a; 1.在平面设计中的应用 2.在插…

跟我学 Java 8 新特性之 Stream 流(二)关键知识点

转载自 跟我学 Java 8 新特性之 Stream 流&#xff08;二&#xff09;关键知识点 我们的第一篇文章&#xff0c;主要是通过一个Demo&#xff0c;让大家体验了一下使用流API的那种酣畅淋漓的感觉。如果你没有实践&#xff0c;我还是再次呼吁你动手敲一敲&#xff0c;自己实实…

mybatis使用注解开发

Mybatis目录 注解开发的crud 1.IUserDao接口中使用注解 2.测试类 注解开发的多表查询 多对一&#xff08;一对一&#xff09; 1.IAccountDao接口中使用注解 2.Account类中&#xff08;从表类&#xff09; 3.测试类 一对多&#xff08;多对多&#xff09; 1.IUserDao接口中使用…

Build 2017 | 微软开发者大会临近,今年的主题是边缘计算

200 多家明星企业&#xff0c;20 位著名投资机构顶级投资人共同参与&#xff01;「新智造成长榜」致力于发掘 AI 领域有 “三年十倍” 成长潜力的创新公司&#xff0c;下一波 AI 独角兽&#xff0c;会有你么&#xff1f;点击加入&#xff01; 雷锋网按&#xff1a;微软首席执行…

Photoshop的基本操作

一、缩放工具 1.缩放工具相当于放大镜和缩小镜&#xff0c;从视觉上改变图像的大小&#xff0c;但实际尺寸并没有改变。 2.快捷键&#xff1a;z或者按住alt鼠标滑轮上滑&#xff08;放大&#xff09;、下滑&#xff08;缩小&#xff09; 二、抓手工具&#xff1a; 1.当图片放大…

JDBC8.0 URL配置

Spring中即成DBUtils <property name"jdbcUrl" value"jdbc:mysql://localhost:3306/eesy_mybatis?useUnicodetrue&amp;characterEncodingUTF-8&amp;serverTimezoneUTC"></property>

王者齐聚!Unite 2017 Shanghai 日程讲师全揭晓

汇聚了来自全球的 Unity开发者、发行商、培训家及爱好者的 Unite 2017 Shanghai 即将于于 5 月 11 日&#xff0d;13日在上海国际会议中心隆重举行。Unite 大会是由 Unity 举办的全球开发者大会&#xff0c;至今已有 10 年历史&#xff0c;并已成为游戏行业、VR/AR 行业最具权威…