java8并行流_Java 8:CompletableFuture与并行流

java8并行流

这篇文章展示了Java 8的CompletableFuture在执行异步计算时如何与并行流进行比较。

我们将使用以下类对长时间运行的任务进行建模:

class MyTask {private final int duration;public MyTask(int duration) {this.duration = duration;}public int calculate() {System.out.println(Thread.currentThread().getName());try {Thread.sleep(duration * 1000);} catch (final InterruptedException e) {throw new RuntimeException(e);}return duration;}
}

让我们创建十个任务,每个任务持续1秒:

List<MyTask> tasks = IntStream.range(0, 10).mapToObj(i -> new MyTask(1)).collect(toList());

我们如何有效地计算任务清单?

方法1:依次

您首先想到的是按顺序计算任务,如下所示:

public static void runSequentially(List<MyTask> tasks) {long start = System.nanoTime();List<Integer> result = tasks.stream().map(MyTask::calculate).collect(toList());long duration = (System.nanoTime() - start) / 1_000_000;System.out.printf("Processed %d tasks in %d millis\n", tasks.size(), duration);System.out.println(result);
}

如您所料,这需要10秒钟才能运行,因为每个任务都在main线程上一个接一个地运行。

方法2:使用并行流

快速改进是将您的代码转换为使用并行流,如下所示:

public static void useParallelStream(List<MyTask> tasks) {long start = System.nanoTime();List<Integer> result = tasks.parallelStream().map(MyTask::calculate).collect(toList());long duration = (System.nanoTime() - start) / 1_000_000;System.out.printf("Processed %d tasks in %d millis\n", tasks.size(), duration);System.out.println(result);
}

输出是

main
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-2
main
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-1
main
Processed 10 tasks in 3043 millis

这次花了3秒,因为并行执行了4个任务(使用了来自ForkJoinPool三个线程以及main线程)。

方法3:使用CompletableFutures

让我们看看CompletableFuture的性能是否更好:

public static void useCompletableFuture(List<MyTask> tasks) {long start = System.nanoTime();List<CompletableFuture<Integer>> futures =tasks.stream().map(t -> CompletableFuture.supplyAsync(() -> t.calculate())).collect(Collectors.toList());List<Integer> result =futures.stream().map(CompletableFuture::join).collect(Collectors.toList());long duration = (System.nanoTime() - start) / 1_000_000;System.out.printf("Processed %d tasks in %d millis\n", tasks.size(), duration);System.out.println(result);
}

在上面的代码中,我们首先获取CompletableFuture的列表,然后在每个CompletableFuture调用join方法以等待它们CompletableFuture完成。 请注意, joinget相同,唯一的区别是前者不引发任何检查的异常,因此在lambda表达式中更为方便。

另外,您必须使用两个单独的流管道,而不是将两个map操作彼此放在后面,因为中间流操作是惰性的,您将不得不按顺序处理任务! 这就是为什么您首先需要在列表中收集CompletableFuture ,以允许它们在等待完成之前启动。

输出是

ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-2
ForkJoinPool.commonPool-worker-3
ForkJoinPool.commonPool-worker-1
Processed 10 tasks in 4010 millis

处理10个任务花了4秒钟。 您会注意到,仅使用了3个ForkJoinPool线程,并且与并行流不同,没有使用main线程。

方法4:将CompletableFutures与自定义执行器一起使用

与并行流相比, CompletableFuture的优点之一是它们允许您指定其他Executor来向其提交任务。 这意味着您可以根据应用程序选择更合适的线程数。 由于我的示例不是很占用CPU,因此可以选择将线程数增加到大于Runtime.getRuntime().getAvailableProcessors() ,如下所示:

public static void useCompletableFutureWithExecutor(List<MyTask> tasks) {long start = System.nanoTime();ExecutorService executor = Executors.newFixedThreadPool(Math.min(tasks.size(), 10));List<CompletableFuture<Integer>> futures =tasks.stream().map(t -> CompletableFuture.supplyAsync(() -> t.calculate(), executor)).collect(Collectors.toList());List<Integer> result =futures.stream().map(CompletableFuture::join).collect(Collectors.toList());long duration = (System.nanoTime() - start) / 1_000_000;System.out.printf("Processed %d tasks in %d millis\n", tasks.size(), duration);System.out.println(result);executor.shutdown();
}

输出是

pool-1-thread-2
pool-1-thread-4
pool-1-thread-3
pool-1-thread-1
pool-1-thread-5
pool-1-thread-6
pool-1-thread-7
pool-1-thread-8
pool-1-thread-9
pool-1-thread-10
Processed 10 tasks in 1009 millis

经过改进,现在仅需1秒即可处理10个任务。

如您所见, CompletableFuture s提供了对线程池大小的更多控制,如果您的任务涉及I / O,则应使用CompletableFuture 。 但是,如果您要执行CPU密集型操作,则线程数不会超过处理器没有意义,因此请选择并行流,因为它更易于使用。

翻译自: https://www.javacodegeeks.com/2016/06/java-8-completablefuture-vs-parallel-stream.html

java8并行流

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

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

相关文章

postgresql删除索引_PostgreSQL 13 发布,索引和查找有重大改进

9月24日&#xff0c;PostgreSQL全球开发组宣布PostgreSQL 13正式发布&#xff0c;作为世界上使用最多的开源数据库之一&#xff0c;PostgresSQL 13是目前的最新版本。PostgreSQL 13 在索引和查找方面进行了重大改进&#xff0c;有利于大型数据库系统&#xff0c;改进包括索引的…

【WebRTC---源码篇】(十六)WebRTC/NetEQ

WebRTC【4096版本】 NetEQ的作用 进行抖动控制和丢包隐藏,通过该技术可以让音频更平滑 NetEQ插入packet数据 int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,rtc::ArrayView<const uint8_t> payload) {//如果有效荷载payload为空if (paylo…

HH SaaS电商系统的销售订单设计

文章目录订单销售类型订单优惠优惠方式子订单优惠金额订单拆单订单发货销售订单拆单逻辑图销售订单的信息结构相关实体订单运营类型&#xff08;作废&#xff09;售后截止时间订单状态状态机的设计不同属性组合下的订单状态组合1&#xff1a;实物线上非预售非定制非拼单快递组合…

kafka netty_惠而浦:使用Netty和Kafka的微服务

kafka netty介绍 在上一个博客中 &#xff0c;我介绍了Netty用作Web服务器。 该示例运行良好……只要需要广播服务器即可。 大多数情况下不是很有用。 更有可能的是&#xff0c;每个客户端仅接收针对其的数据&#xff0c;并保留了特殊情况下的广播&#xff0c;例如“服务器在1…

HH SaaS电商系统的拼团系统设计

文章目录拼团业务流程拼团单实体拼团单的状态拼团型订单的销售状态注意点拼团业务流程 创建活动 管理后台创建拼团活动&#xff0c;设置好活动有效期、成团人数、成团时效、限购数量、活动对象、添加活动商品&#xff0c;设置团长价和团员价&#xff0c;活动开始后活动对象在买…

统信uos系统考试题_离Windows更近一步!微信Linux原生版上线:国产统信UOS系统已适配...

就在本月11号&#xff0c;国产操作系统-统信 UOS发布了专业版 V20(1030)&#xff0c;功能更强大&#xff0c;同时性能和安全性均有所提升。而距离这个好消息过去没多久&#xff0c;统信软件官方再次发布了一个好消息&#xff1a;那就是微信桌面客户端(统信 UOS 版)研发完成&…

npm 引用子项目模块_Java / Web项目中的NPM模块Browser-Sync

npm 引用子项目模块Browser-Sync是一个方便的基于Node.js的NPM模块&#xff0c;可用于更快的Web开发。 浏览器同步可在许多设备之间同步文件更改和交互。 最重要的功能是实时重新加载。 我们也可以在Java / Web项目中使用Browser-Sync。 Cagatay Civici创造了一个伟大的 视频教…

电商系统的自提订单,提货流程如何设计

文章目录产生自提订单的场景非O2O模式平台的自提点和O2O模式平台的自提点区别提货核销二维码核销提货码核销产生自提订单的场景 自提订单通常在O2O场景下会涉及到&#xff0c;所以通常是在O2O店铺会产生这样的订单&#xff0c;当然B2C模式的平台也会产生自提订单&#xff0c;例…

xrd精修教程_XRD精修系列干货 | 带你领略晶体之美

1. XRD精修教程(一)——XRD精修基本原理与GSAS软件简介(附GSAS软件下载链接)点击上图即可查看全文X射线衍射分析(XRD)在研究材料的相结构、相成分等多个方面有广泛的应用&#xff0c;但最常用的多晶衍射法有个缺点&#xff1a;得到的谱峰重叠严重&#xff0c;从而造成大量材料结…

【WebRTC---源码篇】(十八)GoogREMB算法

GoogREMB是基于延时的接收端拥塞控制算法,主要包括以下四个部分: 1.RemoteBitrate Estimator ,是接收端延时拥塞控制算法的管理模块。一方面与外面模块打交道,从网络收/发模块获取RTP包的传输信息用于拥塞评估,或将内部评估的下一时刻的发送码率(大小)输出给网络收/发模…

电商系统的O2O业务模式设计

O2O商业模式简述 O2O模式的平台才会产生配送订单&#xff08;即外卖订单&#xff09;&#xff0c;配送和快递的业务意义不同&#xff0c;配送强调的是“短距离”的派送服务&#xff0c;这正好符合O2O商业模式的核心诉求。 O2O服务的是周边用户人群&#xff0c;满足客户付款后…

cloud foundry_Cloud Foundry Java客户端–流事件

cloud foundryCloud Foundry Java客户端提供了基于Java的绑定&#xff0c;用于与正在运行的Cloud Foundry实例进行交互。 该项目的一件整洁的事情是&#xff0c;它已经接受了基于Reactive Stream的API的方法签名&#xff0c;特别是使用Reactor实现&#xff0c;这在使用流数据时…

多个cpp文件生成so_C++:C++的文件搜索路径

在做大型工程的时候&#xff0c;除了有C语法知识之外&#xff0c;还要有工程能力。最先要具备的能力是&#xff1a;理解C文件的编译&#xff0c;链接过程。明白C头文件的搜索路径。本文&#xff0c;介绍C的文件搜索路径。对于C文件来说&#xff0c;主要有两种&#xff0c;一种是…

【WebRTC---源码篇】(十九)模块的执行-Module

WebRTC中将某些功能划分了模块,现在介绍一下模块是如何执行的。WebRTC中会创建一个线程用于执行模块和异步的任务,模块生成以后注册到线程中,模块执行时会计算下次需要执行的时间,线程根据模块提供的时间会按照指定的时间再次调用模块。线程在处理模块的同时也可以处理其他…

HH SaaS电商系统的店铺系统设计

文章目录为什么店铺运营模式要区分B2C、C2C、O2O&#xff1f;O2O店铺B2C店铺自营B2C店铺第三方B2C店铺C2C店铺为什么O2O店铺不允许售卖快递类的商品&#xff1f;B2C、C2C模式的自提和O2O的自提有什么区别&#xff1f;B2C、C2C模式的配送和O2O的配送有什么区别&#xff1f;为什么…

java 精选选择题_Java生产率提示:社区精选

java 精选选择题社区已经发言。 我们已将您最好和最出色的生产力技巧汇总到一篇文章中。 我们都有自己的小技巧&#xff0c;可以帮助我们提高工作效率&#xff0c;并提高生产率。 我们使用工具来避免繁琐的日常任务&#xff0c;并运行脚本来自动化流程。 我们所做的一切只是为…

监听js变量的变化_JS监听事件型爬虫

点击上方“Python数据科学”&#xff0c;选择“星标公众号”关键时刻&#xff0c;第一时间送达&#xff01;作者&#xff1a;zuobangbang来源&#xff1a;zuobangbang最近开始研究网页参数的JS加密&#xff0c;但是大型网站的JS文件过于繁杂&#xff0c;不适合新手上路&#xf…

HH SaaS电商系统的支付模块设计

文章目录支付单支付单状态流转逻辑说明支付相关实体支付流水记录支付方式支付渠道支付单 销售订单生成时&#xff0c;同步生成支付单&#xff0c;如果销售订单的应付金额由首付款和尾款组成&#xff0c;那么会生成两个支付单 支付单与销售订单的“联合单号”或者“退款单ID”关…

java8 guava_Guavate:桥接Guava和Java8的微型库

java8 guavaJava8很棒&#xff0c;并向JDK添加了一些有用的抽象&#xff0c;这些抽象通过Google出色的Guava commons库在Java社区中得到了普及。 小组讨论表明&#xff0c; 不久将有一个需要Java 8的Guava版本&#xff0c;并弥合了Guava和Java8之间的鸿沟。 但是&#xff0c;直…