Java 8:CompletableFuture与并行流

这篇文章展示了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

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

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

相关文章

linux使用gpio开一个线程,LINUX的gpio_request_one作用

一直习惯使用gpio_request来申请一个GPIO&#xff0c;然后用gpio_direction_input、gpio_direction_output等函数来配置对应的GPIO&#xff0c;用gpio_free来释放申请。后来看到别人也会用gpio_request_one来申请和配置一个GPIO&#xff0c;然后就去看看看这个接口的实现&#…

Python制作回合制手游外挂简单教程(下)

引入&#xff1a; 接着上篇的博文&#xff0c;今天我们讲如何实现助人为乐 前期准备&#xff1a; 如何获取图片中指定文字的坐标&#xff1f; 我的思路是截取一个小区域&#xff0c;再根据小区域左上角的坐标获取中央坐标 例如&#xff1a; 获取坐上角的x和y坐标&#xff0c;测…

XSHELL下直接下载文件到本地(Windows)

转载自&#xff1a;http://www.cnblogs.com/davytitan/p/3966606.html xshell很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz 首先你的Ubuntu需要安装rz.sz(如果没有安装请执行以下命令,安装完的请跳过.其它版本linux请自行安装相应软…

linux操作系统2试题,RedHat Linux 9.0 操作系统测试题2

一、填空题(每空1分&#xff0c;共14分)1.任何Linux系统都至少需要两类分区&#xff1a;根分区和交换分区。2.CD-ROM标准的文件系统是iso9660。3.使用vi编辑器可以创建文本文件&#xff0c;在输入文件内容之前需要先按INSERT键进入插入模式&#xff0c;在保存之前需下先使用ESC…

HazelCast的Spring-Boot和Cache抽象

以前&#xff0c;我们是使用spring提供的默认Cache Manager来开始Spring Cache抽象的。 尽管这种方法可能适合我们对简单应用程序的需求&#xff0c;但是在出现复杂问题的情况下&#xff0c;我们需要使用具有更多功能的其他工具。 Hazelcast就是其中之一。 当涉及到基于JVM的应…

Ubuntu18.04 安装搜狗输入法后无法启动的问题

ibus 改选成fcitx后搜狗输入法照样没出来。 这里需要im-config 没有的话需要安装&#xff1a; sudo apt install im-config 然后在Terminal中执行 im-config 根据提示选择fcitx转载于:https://www.cnblogs.com/feipeng8848/p/9609877.html

linux华为路由器模拟器,华为路由器模拟器与实验内容.doc

华为路由器模拟器与实验内容华为的路由器模拟器及实验内容??2009-12-21 20:27:53|??分类&#xff1a; HYPERLINK "/ah..zhangrui/blog/" \l "m0&t1&cfks_080074086080086074092094074070087095083070092086084" \o "默认分类" 默认分…

_WIN32_WCE有什么用

转载自&#xff1a;http://blog.csdn.net/thanklife/article/details/21477561 _WIN32_WCE有什么用,我这里找了一些人的回应。由于目前我手头的源码有限&#xff0c;还没有找到定义之处。先这样保留着这个问题吧。以下是一些别人给的认识。 经常看到 #ifndef _WIN32_WCE 这是什…

zk ui_高级ZK:异步UI更新和后台处理–第1部分

zk ui异步UI更新非常有用&#xff0c;因为它们通常可以提高响应性&#xff0c;可用性和用户界面的总体感觉。 我将在这里重点介绍ZK框架&#xff0c;但是通常&#xff0c;相同的原理也适用于桌面UI&#xff08;Swing&#xff0c;SWT&#xff09;。 长时间运行的处理 有时您可能…

BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6881 Solved: 4213[Submit][Status][Discuss]Description 您需要写一种数据结构&#xff08;可参考题目标题&#xff09;&#xff0c;来维护一个有序数列&#xff0c;其中需要提供以下操作&#…

在Spring中了解事务注释

1.简介 Spring为程序性和声明性事务提供支持。 1.1程序化交易 对于程序性事务&#xff0c;需要显式编写事务管理代码&#xff0c;以便在一切成功后提交&#xff0c;并在出现问题时回滚。 在这种情况下&#xff0c;事务管理代码与业务逻辑紧密绑定。 1.2声明式交易 声明式事…

GIS开源库shapeLib的使用方法

转自&#xff1a;http://www.cnblogs.com/liongis/archive/2012/10/23/2736015.html 近期研究了一下GIS开源库shapeLib读写ArcGIS数据的API函数&#xff0c;先整理一下&#xff0c;将各个API的用法介绍一下。 分为两个模块&#xff0c;shape API和DBF API&#xff0c;前者的读取…

linux 升级 iphone,Linux 5.13 更新有望增加对苹果 M1 处理器的支持

IT之家 4 月 10 日消息 预计 Linux 5.13 将初步支持苹果 Silicon M1 处理器&#xff0c;不过可能还需要几年时间才能完全支持。虽然已经在苹果 Silicon M1 上运行&#xff0c;但这是通过一系列的补丁&#xff0c;单纯是为了 Linux 能够在 M1 设备上启动而已&#xff0c;而现在 …

201771010118马昕璐

第一部分 理论知识的学习 第三章Java基本程序设计结构 1 基本知识&#xff1a; &#xff08;1&#xff09;标识符&#xff1a;标识符由字母、下划线、美元符号和数字组成&#xff0c;且第一个符号不能为数字。Hello、$1234、程序名、www_123都是合法标识符。 标识符可用作类名…

Xshell显示中文乱码问题

转载自&#xff1a;http://www.blogjava.net/RoyPayne/archive/2011/12/21/366899.htmlXshell对于嵌入式开发来说&#xff0c;是个非常不错的工具。但或许都有过被中文显示为乱码的问题感觉有点不爽。解决方法其实很简单的&#xff0c;即把xshell编码方式改成UTF-8即可。 [文…

apache wicket_Apache Wicket:记住我的功能

apache wicket在Web应用程序中&#xff0c;很常见的是具有“记住我”功能&#xff0c;该功能使用户每次访问我们的网站时都能自动登录。 可以使用Spring Security来实现这种功能&#xff0c;但我认为将基于请求的身份验证框架与基于组件的Web框架一起使用并不是最好的主意。 这…

linux pap认证,配置PPP PAP 认证

配置PPP PAP 认证&#xff1a;1. 单向认证&#xff1a;R1启动pap R1为主验证方&#xff0c;R2为被验证方。r1(config)#inter s1/0r1(config-if)#ip add 202.146.0.1 255.255.255.0r1(config-if)#no shutdownr1(config-if)#encapsulation pppr1(config-if)#ppp authenticatin pa…

Shell编程关于Sha-Bang(#!)

转载自&#xff1a;http://blog.chinaunix.net/uid-26657936-id-3066136.html Q. #!的名字为什么叫Sha-Bang&#xff1f; A. Sha-Bang是Sharp和Bang的组合词。Sharp for #, Bang for ! 类似的情况是&#xff0c;C#通常被称为C SharpQ. Sha-Bang(#!)是不是注释&#xff1f;A. 不…

您应该保持联系的十大高级Java对话

在线讲座和视频是学习软件开发新事物的主要资源之一。 您可以找到Java专家与您分享他们的经验&#xff0c;而不必坐下来。 在下面的文章中&#xff0c;我们收集了10位我们最喜欢的演讲者和主题&#xff0c;我们相信每个Java开发人员都应该注意。 获取爆米花&#xff0c;坐下来…

c语言定时器作用,Go语言定时器实现原理及作用

对于任何一个正在运行的应用&#xff0c;如何获取准确的绝对时间都非常重要&#xff0c;但是在一个分布式系统中我们很难保证各个节点上绝对时间的一致性&#xff0c;哪怕通过 NTP 这种标准的对时协议也只能把时间的误差控制在毫秒级&#xff0c;所以相对时间在一个分布式系统中…