文档章节

Java8的CompletableFuture

pior
 pior
发布于 2015/06/05 15:28
字数 2018
阅读 223
收藏 2

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

异步编程的难点 如何优雅地实现异步编程一直都是一个难题,异步编程的通常做法就是采用的方法,但是这种方法通常会把代码嵌套在正常流程的代码中,而且当有多层嵌套的时候代码更加难以维护。...

SevenLin1993
08/20
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

没有更多内容

加载失败,请刷新页面

加载更多

Redis常用命令

keys 我把这个命令放在第一位,是因为笔者曾经做过的项目,以及一些朋友的项目,都因为使用keys这个命令,导致出现性能毛刺。这个命令的时间复杂度是O(N),而且redis又是单线程执行,在执行k...

谢思华
42分钟前
2
0
关于css宽度分离

所谓宽度分离就是width 属性不与影响宽度的 padding/border(有时候包括 margin)属性共存 例如: .box{width:200px;padding:20px;border:1px solid;} 为何要做宽度分离 一说到分离就是为了好...

莫西摩西
52分钟前
1
0
Linux常用命令

###############常用命令说明############################## cat /proc/version 显示内核的版本 mv dir1 new_dir 重命名/移动 一个目录 rm -rf a.txt b.txt c.txt 删除多个文件 chmod 777 ......

lyle_luo
59分钟前
3
0
全国地区代码科普

全国地区代码表 天津市 地区代码 地区名称 1100 天津市 辽宁省 地区代码 地区名称 2210 沈阳市 2210 法库县 2210 康平县 2210 辽中县 2210 新民市 2220 大连市 2222 普兰店市 2223 庄河市 22...

恋码之子
今天
1
0
DbForge Schema Compare for MySQL入门教程:生成比较报告

【dbForge Schema Compare for MySQL下载】 当架构比较完成后,您可以生成比较报告以保留架构更改的记录。 1. 在“Comparison” 菜单中,单击“Generate Comparison Report” 。将打开“Gen...

Miss_Hello_World
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部