文档章节

Java8的CompletableFuture

pior
 pior
发布于 2015/06/05 15:28
字数 2018
阅读 194
收藏 2
点赞 0
评论 0

CompletableFuture是Java8新加入的异步工具类,扩展了Future,吸纳了一些第三方类库的特性。

来看一下这个类的方法列表:

是不是看着就很强大,嗯 ,让我们开始。。

等等,异步工具是个啥? 

他可以说就是你雇来的特工,把要交付的东西交代清楚了以后,只需在你方便的时候等他给你交货,也可以直接告诉货么了怎么处理。在这期间,你自己想干啥干啥,特工自己会去完成任务。

嗯,可以开始了。。

创建一个CompletableFuture

还可以用静态方法来创建,让他给我搞到10W刀:

CompletableFuture<String> future = CompletableFuture
			.supplyAsync(() -> "$100,000");

这里用的是supplyAsync(),传给它的参数是一个lambda,返回"$100,000"。

还有一个类似的静态方法:

CompletableFuture<Void> future = CompletableFuture
			.runAsync(() -> System.out.println("mission complet!"));

runAsync()与supplyAsync()的区别在于他不能提供返回值。范型为Void。

这里还有另一个静态方法:

CompletableFuture<Integer> future = CompletableFuture
		.completedFuture(100);

这里以创建一个直接返回结果的future。这有啥用呢。往后看。

安排工作

对于创建时没有安排工作的特工,还要有一步布置任务:

CompletableFuture<Integer> future = CompletableFuture
		.completedFuture(100);
future.handle((i, ex) -> 100 * i);

handle()方法,给特工安排任务。参数类型为BiFunction<? super T, Throwable, ? extends U> fn。

这里直接返回了i的100倍。这个i,就是前面completedFuture(100)里的100。

也就是说,handle是拿之前future的执行结果和异常信息交给下一个特工继续进行任务。

注意,这里是指的下一个特工,也就是这原来的特工还是只返回了100,乘100倍的事是另一个人干的。也就是handle()方法的返回值。正确的打开方式是这样的:

CompletableFuture<Integer> future = CompletableFuture
		.completedFuture(100);
CompletableFuture<Integer> future2 = future.handle((i, ex) -> 100 * i);


去干活吧

有了已经安排好工作的特工,让我们看看怎么让他们开始干活,啥?他们在到任务的时候已经出发了?

看下面这个代码:

CompletableFuture<String> future = CompletableFuture
		.supplyAsync(() -> {
			String money = "$0";
			for (int i = 10000; i <= 100000; i += 10000) {
				try {
					Thread.sleep(1000);
				} catch (Exception e) {
				}
				money = "$" + i;
				System.out.println("得到钱:" + money);
			}
			return money;
		});

IntStream.range(1, 10).forEach((n) -> {
	System.out.println("到 " + n + " 号店面收帐.");
	try {
		Thread.sleep(1000);
	} catch (Exception e) {
	}
});

特工的任务去给我搞钱,他要分10次搞到10W刀,钱不是这么好搞的,所以要花点时间。

交代给他任务以后,我就去各个店面里收帐了,10个店面转一圈,也是要花点时间的。

看输出结果:

到 1 号店面收帐.
得到钱:$10000
到 2 号店面收帐.
得到钱:$20000
到 3 号店面收帐.
得到钱:$30000
到 4 号店面收帐.
得到钱:$40000
到 5 号店面收帐.
得到钱:$50000
到 6 号店面收帐.
得到钱:$60000
到 7 号店面收帐.
得到钱:$70000
到 8 号店面收帐.
得到钱:$80000
到 9 号店面收帐.
得到钱:$90000

是并发的,也就是说,我收帐的同时特工也在给我去搞钱。

想想就开心。

那特工搞到的钱。怎么给我呢??

获取结果

CompletableFuture<String> future = CompletableFuture
		.supplyAsync(() -> "$100,000");
String getString = future.get();
System.out.println(getString);

最直接的方式就是和Future一样,用get()方法,从Future里货取返回值。10W刀到手了。

CompletableFuture还有一个独有的方法:join(),和get()的功能类似。与是从Future里货取返回值。

CompletableFuture<String> future = CompletableFuture
		.supplyAsync(() -> "$100,000");
String getString = future.join();
System.out.println(getString);

区别就是,join()不会像get()抛出ExecutionException,那特工任务在执行过程中出现问题怎么处理?这个后面会讲。

嗯,我们现在把另一个特工也让他去干活吧。

CompletableFuture<Integer> future = CompletableFuture
		.completedFuture(100);
CompletableFuture<Integer> future2 = future.handle((i, ex) -> 100 * i);
Integer getInteger = future2.join();
System.out.println(getInteger);

这里得到了10000,如果调用future.join()呢?只有100。

想要的结果有了,还有个问题,现在用join()的方式 ,是和特工约好在我收完账以后见面,不见不散的那种,同步死等。

比如把前面那个收钱的代码改一下。等从特工处收到钱以后,我还要再去别的店里收账。

CompletableFuture<Integer> future = CompletableFuture
		.supplyAsync(() -> {
			int money = 0;
			for (money = 10000; money <= 100000; money += 10000) {
				try {
					Thread.sleep(2000);
				} catch (Exception e) {
				}
				System.out.println("特工得到钱:$" + money);
			}
			return money;
		});
int myMoney = 0;
int n = 0;
for (n = 1; n <= 10; n++) {
	myMoney += 1000;
	System.out.println("到 " + n + " 号店面收帐,我得到钱:$" + myMoney);
	try {
		Thread.sleep(1000);
	} catch (Exception e) {
	}
}

int getMoney = future.join();
System.out.println("我从特工处收获:" + getMoney);
System.out.println("一起存入银行:" + (getMoney + myMoney));
System.out.println("继续收线");
myMoney = 0;
for (; n <= 20; n++) {
	myMoney += 1000;
	System.out.println("到 " + n + " 号店面收帐,我得到钱:$" + myMoney);
	try {
		Thread.sleep(1000);
	} catch (Exception e) {
	}
}

输出如下:

到 1 号店面收帐,我得到钱:$1000
到 2 号店面收帐,我得到钱:$2000
特工得到钱:$10000
到 3 号店面收帐,我得到钱:$3000
到 4 号店面收帐,我得到钱:$4000
特工得到钱:$20000
到 5 号店面收帐,我得到钱:$5000
到 6 号店面收帐,我得到钱:$6000
特工得到钱:$30000
到 7 号店面收帐,我得到钱:$7000
到 8 号店面收帐,我得到钱:$8000
特工得到钱:$40000
到 9 号店面收帐,我得到钱:$9000
到 10 号店面收帐,我得到钱:$10000
特工得到钱:$50000
特工得到钱:$60000
特工得到钱:$70000
特工得到钱:$80000
特工得到钱:$90000
特工得到钱:$100000
我从特工处收获:110000
一起存入银行:120000
继续收线
到 11 号店面收帐,我得到钱:$1000
到 12 号店面收帐,我得到钱:$2000
到 13 号店面收帐,我得到钱:$3000
到 14 号店面收帐,我得到钱:$4000
到 15 号店面收帐,我得到钱:$5000
到 16 号店面收帐,我得到钱:$6000
到 17 号店面收帐,我得到钱:$7000
到 18 号店面收帐,我得到钱:$8000
到 19 号店面收帐,我得到钱:$9000
到 20 号店面收帐,我得到钱:$10000

能看出,由于特工的速度慢,我要等他交付以后才能继续收账。

如果见面后的工作是很简单的事,能不能交代给特工做,我就不用等着了,可以继续去干别的。

CompletableFuture<Integer> future = CompletableFuture
				.supplyAsync(() -> {
					int money = 0;
					for (money = 10000; money <= 100000; money += 10000) {
						try {
							Thread.sleep(2000);
						} catch (Exception e) {
						}
						System.out.println("特工得到钱:$" + money);
					}
					return money;
				});
		int myMoney = 0;
		int n = 0;
		for (n = 1; n <= 10; n++) {
			myMoney += 1000;
			System.out.println("到 " + n + " 号店面收帐,我得到钱:$" + myMoney);
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
		}

		final int partMoney = myMoney;
		future.thenAcceptAsync((money) -> {
			System.out.println("我从特工处收获:" + money);
			System.out.println("一起存入银行:" + (money + partMoney));
		});

		System.out.println("继续收线");
		myMoney = 0;
		for (; n <= 20; n++) {
			myMoney += 1000;
			System.out.println("到 " + n + " 号店面收帐,我得到钱:$" + myMoney);
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
		}

用thenAcceptAsync()方法把完成以后的工作交付给特工,就可以继续去收账了。只不过这里的partMoney要是final的,看输出:

到 1 号店面收帐,我得到钱:$1000
到 2 号店面收帐,我得到钱:$2000
到 3 号店面收帐,我得到钱:$3000
特工得到钱:$10000
到 4 号店面收帐,我得到钱:$4000
特工得到钱:$20000
到 5 号店面收帐,我得到钱:$5000
到 6 号店面收帐,我得到钱:$6000
特工得到钱:$30000
到 7 号店面收帐,我得到钱:$7000
到 8 号店面收帐,我得到钱:$8000
特工得到钱:$40000
到 9 号店面收帐,我得到钱:$9000
到 10 号店面收帐,我得到钱:$10000
特工得到钱:$50000
继续收线
到 11 号店面收帐,我得到钱:$1000
到 12 号店面收帐,我得到钱:$2000
特工得到钱:$60000
到 13 号店面收帐,我得到钱:$3000
到 14 号店面收帐,我得到钱:$4000
特工得到钱:$70000
到 15 号店面收帐,我得到钱:$5000
到 16 号店面收帐,我得到钱:$6000
特工得到钱:$80000
到 17 号店面收帐,我得到钱:$7000
到 18 号店面收帐,我得到钱:$8000
特工得到钱:$90000
到 19 号店面收帐,我得到钱:$9000
到 20 号店面收帐,我得到钱:$10000
特工得到钱:$100000
我从特工处收获:110000
一起存入银行:120000





© 著作权归作者所有

共有 人打赏支持
pior
粉丝 25
博文 151
码字总数 22496
作品 0
济南
高级程序员
Java8新的异步编程方式 CompletableFuture(三)

前面两篇文章已经整理了CompletableFuture大部分的特性,本文会整理完CompletableFuture余下的特性,以及将它跟RxJava进行比较。 3.6 Either Either 表示的是两个CompletableFuture,当其中任...

Tony沈哲
2017/10/21
0
0
Java8新的异步编程方式 CompletableFuture(三)

前面两篇文章已经整理了CompletableFuture大部分的特性,本文会整理完CompletableFuture余下的特性,以及将它跟RxJava进行比较。 3.6 Either Either 表示的是两个CompletableFuture,当其中任...

fengzhizi715
2017/09/24
0
0
Java8新特性之:CompletableFuture

一. CompletableFuture 1.Future接口 Future设计的初衷:对将来某个时刻会发生的结果进行建模。 它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。...

Turnsole1
05/27
0
0
Java8新的异步编程方式 CompletableFuture(二)

上一篇文章,讲述了Future模式的机制、缺点,CompletableFuture产生的由来、静态工厂方法、complete()方法等等。 本文将继续整理CompletableFuture的特性。 3.3 转换 我们可以通过Completab...

Tony沈哲
2017/10/21
0
0
Java8新特性--使用CompletableFuture构建异步应用

原文链接:http://www.jianshu.com/p/4897ccdcb278 Future 接口的局限性 future接口可以构建异步应用,但依然有其局限性。它很难直接表述多个Future 结果之间的依赖性。实际开发中,我们经常需...

关河
2017/10/27
0
0
对协程的一些理解

协程 协程(coroutine)最早由Melvin Conway在1963年提出并实现,一句话定义:协程是用户态的轻量级的线程 线程和协程 线程和协程经常被放在一起比较;线程一旦被创建出来,编写者是无法决定什...

ksfzhaohui
2016/12/09
4.6K
16
Java8新的异步编程方式 CompletableFuture(一)

一. Future JDK 5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。 Future模式是多线程设计常用的一种设计模式。Future模式可...

Tony沈哲
2017/10/21
0
0
IntelliJ IDEA 2017.1 EAP与异步堆栈跟踪调试器扩展

早些时候java8介绍了CompletableFuture(采用Guava’s ListenableFuture),通过Akka, Ratpack, Reactor, RxJava, Vert.x以及其它库实现反应流。虽然反应性编程能帮助我们构建高效的应用程序...

力谱宿云
2017/02/21
390
2
Java线程的JDK8对并发的新支持

LongAdder 和AtomicLong类似的使用方式,但是性能比AtomicLong更好。 LongAdder与AtomicLong都是使用了原子操作来提高性能。但是LongAdder在AtomicLong的基础上进行了热点分离,热点分离类似...

Jansens
2016/11/28
15
0
[高并发Java 十] JDK8对并发的新支持

LongAdder 和AtomicLong类似的使用方式,但是性能比AtomicLong更好。 LongAdder与AtomicLong都是使用了原子操作来提高性能。但是LongAdder在AtomicLong的基础上进行了热点分离,热点分离类似...

Hosee
2016/02/16
6.4K
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

机器学习管理平台 MLFlow

最近工作很忙,博客一直都没有更新。抽时间给大家介绍一下Databrick开源的机器学习管理平台-MLFlow。 谈起Databrick,相信即使是不熟悉机器学习和大数据的工程湿们也都有所了解,它由Spark的...

naughty
今天
0
0
idea tomcat 远程调试

tomcat 配置 编辑文件${tomcat_home}/bin/catalina.sh,在文件开头添加如下代码。    CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7829" Idea端配......

qwfys
今天
1
0
遍历目录下的文件每250M打包一个文件

#!/usr/bin/env python # -*- utf-8 -*- # @Time : 2018/7/20 0020 下午 10:16 # @Author : 陈元 # @Email : abcmeabc@163.com # @file : tarFile.py import os import tarfile import thr......

寻爱的小草
今天
1
0
expect同步文件&expect指定host和要同步的文件&构建文件分发系统&批量远程执行命令

20.31 expect脚本同步文件 expect通过与rsync结合,可以在一台机器上把文件自动同步到多台机器上 编写脚本 [root@linux-5 ~]# cd /usr/local/sbin[root@linux-5 sbin]# vim 4.expect#!/...

影夜Linux
今天
1
0
SpringBoot | 第九章:Mybatis-plus的集成和使用

前言 本章节开始介绍数据访问方面的相关知识点。对于后端开发者而言,和数据库打交道是每天都在进行的,所以一个好用的ORM框架是很有必要的。目前,绝大部分公司都选择MyBatis框架作为底层数...

oKong
今天
13
0
win10 上安装解压版mysql

1.效果 2. 下载MySQL 压缩版 下载地址: https://downloads.mysql.com/archives/community/ 3. 配置 3.1 将下载的文件解压到合适的位置 我最终将myql文件 放在:D:\develop\mysql 最终放的位...

Lucky_Me
今天
2
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

问题终结者
今天
2
0
expect脚本同步文件expect脚本指定host和要同步的文件 构建文件分发系统批量远程执行命令

expect脚本同步文件 在一台机器上把文件同步到多台机器上 自动同步文件 vim 4.expect [root@yong-01 sbin]# vim 4.expect#!/usr/bin/expectset passwd "20655739"spawn rsync -av ro...

lyy549745
今天
1
0
36.rsync下 日志 screen

10.32/10.33 rsync通过服务同步 10.34 linux系统日志 10.35 screen工具 10.32/10.33 rsync通过服务同步: rsync还可以通过服务的方式同步。那需要开启一个服务,他的架构是cs架构,客户端服务...

王鑫linux
今天
1
0
matplotlib 保存图片时的参数

简单绘图 import matplotlib.pyplot as pltplt.plot(range(10)) 保存为csv格式,放大后依然很清晰 plt.savefig('t1.svg') 普通保存放大后会有点模糊文件大小20多k plt.savefig('t5.p...

阿豪boy
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部