CompletableFuture用法介绍
一、CompletableFuture用法入门介绍
入门介绍的一个例子:
package com.cy.java8; import java.util.Random;
import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction {
private final static Random RANDOM = new Random(System.currentTimeMillis()); public static void main(String[] args){
CompletableFuture<Double> completableFuture = new CompletableFuture<>();
new Thread(() -> {
double value = get();
completableFuture.complete(value);
}).start(); System.out.println("do other things..."); completableFuture.whenComplete((t, e) -> {
System.out.println("complete. value = "+ t);
if(e != null){
e.printStackTrace();
}
});
} private static double get(){
try {
Thread.sleep(RANDOM.nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return RANDOM.nextDouble();
}
}
console打印:
do other things...
complete. value = 0.8244376567363494
二、CompletableFuture.supplyAsync
CompletableFuture很少有直接new出来的方式去用的,一般都是通过提供的静态方法来使用。
1.使用CompletableFuture.supplyAsync来构造CompletableFuture:
package com.cy.java8; import java.util.concurrent.*; import static com.cy.java8.CompletableFutureInAction.get; public class CompletableFutureInAction2 { public static void main(String[] args) {
/**
* 可以发现value=..没有被打印,为什么呢?
* 因为此方法构造出来的线程是demon的,守护进程,main执行结束之后就消失了,所以
* 根本没来得及执行whenComplete中的语句
*/
CompletableFuture.supplyAsync(() -> get())
.whenComplete((v, e) -> {
System.out.println("value = " + v);
if (e != null) {
e.printStackTrace();
}
}); System.out.println("do other things...");
} }
2.要将上面whenComplete中的语句执行,进行改造:
package com.cy.java8; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.cy.java8.CompletableFutureInAction.get; public class CompletableFutureInAction2 { public static void main(String[] args) throws InterruptedException {
AtomicBoolean finished = new AtomicBoolean(false); CompletableFuture.supplyAsync(() -> get())
.whenComplete((v, e) -> {
System.out.println("value = " + v);
if (e != null) {
e.printStackTrace();
}
finished.set(true);
}); System.out.println("do other things..."); while(!finished.get()){
Thread.sleep(1);
}
} }
改写之后, main线程发现如果finished没有变为true就会一直等1ms,直到whenComplete执行将finished变为true。
3.上面的改写很low,其实只要将守护线程变为前台进程,main结束后不会消失就行了。
package com.cy.java8; import java.util.concurrent.*;
import static com.cy.java8.CompletableFutureInAction.get; public class CompletableFutureInAction2 { public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(2, r -> {
Thread t = new Thread(r);
t.setDaemon(false); //非守护线程
return t;
}); CompletableFuture.supplyAsync(() -> get(), executorService)
.whenComplete((v, e) -> {
System.out.println("value = " + v);
if (e != null) {
e.printStackTrace();
}
}); System.out.println("do other things..."); //main执行结束之后,executorService线程不会结束,需要手动shutdown
executorService.shutdown();
} }
三、thenApply:
package com.cy.java8; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CompletableFutureInAction3 { public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2, r -> {
Thread t = new Thread(r);
t.setDaemon(false);
return t;
}); /**
* 将执行完的结果再*100
*/
CompletableFuture.supplyAsync(CompletableFutureInAction::get, executor)
.thenApply(v -> multiply(v))
.whenComplete((v, e) -> System.out.println(v));
} private static double multiply(double value){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return value * 100;
} }
console打印:
43.15351824222534
四、CompletableFuture.join()
package com.cy.java8; import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors; public class CompletableFutureInAction3 { public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2, r -> {
Thread t = new Thread(r);
t.setDaemon(false);
return t;
}); /**
* 需求:将一组商品列表里面的每个商品对应的价格查询出来,并将这个价格*100.
* 5个商品同时并发去做这件事
*
* CompletableFuture.join():等到所有的结果都执行结束,会返回CompletableFuture自己本身
* 执行完的结果,等于get()返回的结果。
*/
List<Integer> productionIDs = Arrays.asList(1, 2, 3, 4, 5); //待查的一组商品列表的ID
List<Double> priceList = productionIDs.stream().map(id -> CompletableFuture.supplyAsync(() -> queryProduction(id), executor))
.map(future -> future.thenApply(price -> multiply(price)))
.map(multiplyFuture -> multiplyFuture.join())
.collect(Collectors.toList());
System.out.println(priceList); /**
* 按照以前,要5个分别for循环去查询
* 或者分多个线程去查询,再将每个线程查询的结果汇总,等到全部线程都执行完了,结果也就出来了
*/
} private static double multiply(double value) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return value * 100;
} /**
* 模拟 根据商品id查询对应的价格
* @param id
* @return
*/
private static double queryProduction(int id){
return CompletableFutureInAction.get();
}
}
console打印:
[90.93730009374265, 23.65282935900653, 17.415066430776815, 16.605197824452343, 60.143109082288206]
说明:这里多个任务同时执行,最终把结果汇总到一起 ,这种都是并行去执行的,编写代码也比较简洁,不需要考虑多线程之间的一些交互、锁、多线程之间的通信、控制,都不需要去关心。
五、CompletableFuture的常用API介绍
supplyAsync
thenApply
whenComplete
handle
thenRun
thenAccept
thenCompose
thenCombine
thenAcceptBoth
runAfterBoth
applyToEither
acceptEither
runAfterEither
anyOf
allOf
1)supplyAsync、thenApply、whenComplete前面的代码已经介绍了。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.thenApply(v -> Integer.sum(v,10))
.whenComplete((v, e) -> System.out.println(v)); Thread.sleep(1000);
}
}
2)whenCompleteAsync: whenComplete是同步的方式,如果对于结果的处理是比较占时间的,不想通过这种同步的方式去做,可以用whenCompleteAsync进行异步操作。
3)handle:和thenApply差不多,只是多了一个对于异常的考虑。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.handle((v, e) -> Integer.sum(v, 10))
.whenComplete((v, e) -> System.out.println(v)); Thread.sleep(1000);
}
}
4)thenRun:如果想在completableFuture整个执行结束之后,还想进行一个操作,可以thenRun(Runnable r)
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.handle((v, e) -> Integer.sum(v, 10))
.whenComplete((v, e) -> System.out.println(v))
.thenRun(()-> System.out.println("thenRunning...")); Thread.sleep(1000);
}
}
11
thenRunning...
5)thenAccept: thenAccept(Consumer c)里面传的是consumer,对执行结果进行消费,不会对执行结果进行任何操作。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.thenApply(v -> Integer.sum(v, 10))
.thenAccept(System.out::println); Thread.sleep(1000);
}
}
11
6)thenCompose: 对执行结果再交给另外一个CompletableFuture,它再去对这个执行结果进行另外的计算。compose:组合,组合设计模式。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.thenCompose(v -> CompletableFuture.supplyAsync(() -> v * 10))
.thenAccept(System.out::println); Thread.sleep(1000);
}
}
10
7)thenCombine: thenCombine(CompletableFuture extends CompletionStage, BiFuntion)
CompletableFuture的计算结果v1作为BiFunction的第1个入参,thenCombine中的第一个参数CompletableFuture的计算结果v2作为BiFunction的第2个入参,biFunction进行操作然后返回结果。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.thenCombine(CompletableFuture.supplyAsync(() -> 2.0), (v1, v2) -> v1 + v2)
.thenAccept(System.out::println); Thread.sleep(1000);
}
}
3.0
8)thenAcceptBoth: 和thenCombine差不多,只不过它的第二个参数是BiConsumer
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction4 {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> 1)
.thenAcceptBoth(CompletableFuture.supplyAsync(() -> 2.0), (v1, v2) -> {
System.out.println("value=" + (v1 + v2));
}); Thread.sleep(1000);
}
}
value=3.0
9)runAfterBoth:两个CompletableFuture都执行结束之后,run
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction5 {
public static void main(String[] args) throws InterruptedException { CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " is running");
return 1;
}).runAfterBoth(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " is running too");
return 2;
}), () -> System.out.println("both done")); Thread.sleep(1000);
}
}
ForkJoinPool.commonPool-worker-9 is running
ForkJoinPool.commonPool-worker-9 is running too
both done
10)applyToEither
applyToEither:两个CompletableFuture只要有1个执行完了,就将这个CompletableFuture交给Function。谁先执行完就将谁交给Function去执行
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction5 {
public static void main(String[] args) throws InterruptedException { CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 1");
return 1;
}).applyToEither(CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 2");
return 2;
}), v -> {
System.out.println("value = " + v);
return v * 10;
}).thenAccept(System.out::println); Thread.currentThread().join();
}
}
I am future 2
value = 2
20
I am future 1
11)acceptEither
acceptEither:acceptEither(CompletableFuture extends CompletionStage, Consumer), 两个CompletableFuture谁先执行完成,就将谁的结果交给consumer执行。
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction5 {
public static void main(String[] args) throws InterruptedException { CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 1");
return 1;
}).acceptEither(CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 2");
return 2;
}), v -> System.out.println("value = " + v)); Thread.currentThread().join();
}
}
I am future 2
value = 2
I am future 1
12)runAfterEither
runAfterEither: runAfterEither(CompletionStage, Runnable),只要有一个CompletableFuture执行完了,就执行run
package com.cy.java8; import java.util.concurrent.CompletableFuture; public class CompletableFutureInAction5 {
public static void main(String[] args) throws InterruptedException { CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 1");
return 1;
}).runAfterEither(CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am future 2");
return 2;
}), () -> System.out.println("done.")); Thread.currentThread().join();
}
}
I am future 2
done.
I am future 1
13)allOf
allOf(CompletableFuture<?>... cfs),返回值是CompletableFuture<Void>。要等所有的CompletableFuture都执行完成,才能执行下一步动作。
package com.cy.java8; import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; public class CompletableFutureInAction5 {
private final static Random RANDOM = new Random(System.currentTimeMillis()); public static void main(String[] args) throws InterruptedException {
List<CompletableFuture<Double>> list = Arrays.asList(1, 2, 3, 4).stream()
.map(i -> CompletableFuture.supplyAsync(CompletableFutureInAction5::get))
.collect(Collectors.toList()); //要等所有的CompletableFuture这些task执行完了,才会打印done.
CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()]))
.thenRun(() -> System.out.println("done.")); Thread.currentThread().join();
} static double get() {
try {
Thread.sleep(RANDOM.nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
double result = RANDOM.nextDouble();
System.out.println(result);
return result;
}
}
0.6446554001163166
0.24435437709196395
0.18251850071600362
0.5261702037394511
done.
14)anyOf
和allOf相反,只要有一个CompletableFuture执行完成,就会执行下一步动作
package com.cy.java8; import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; public class CompletableFutureInAction5 {
private final static Random RANDOM = new Random(System.currentTimeMillis()); public static void main(String[] args) throws InterruptedException {
List<CompletableFuture<Double>> list = Arrays.asList(1, 2, 3, 4).stream()
.map(i -> CompletableFuture.supplyAsync(CompletableFutureInAction5::get))
.collect(Collectors.toList()); //只要有一个CompletableFuture执行完了,就会打印done.
CompletableFuture.anyOf(list.toArray(new CompletableFuture[list.size()]))
.thenRun(() -> System.out.println("done.")); Thread.currentThread().join();
} static double get() {
try {
Thread.sleep(RANDOM.nextInt(3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
double result = RANDOM.nextDouble();
System.out.println(result);
return result;
}
}
0.1334361442807943
done.
0.6715112881360222
0.12945359790698785
0.1307762755130788
----
CompletableFuture用法介绍的更多相关文章
- 好压(HaoZip)的命令行模式用法介绍
好压压缩软件,又叫“2345好压”,是一款国产的优秀压缩软件,目前是免费的,据官网介绍,该软件永久免费.官网地址:http://haozip.2345.com/ 本文主要对该软件的命令行模式用法进行介 ...
- sql事务(Transaction)用法介绍及回滚实例
sql事务(Transaction)用法介绍及回滚实例 事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务, S ...
- STL vector用法介绍
STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...
- 怎么通过activity里面的一个按钮跳转到另一个fragment(android FragmentTransaction.replace的用法介绍)
即:android FragmentTransaction.replace的用法介绍 Fragment的生命周期和它的宿主Activity密切相关,几乎和宿主Activity的生命周期一致,他们之间最 ...
- Oracle CASE WHEN 用法介绍[Z]
Oracle CASE WHEN 用法介绍 1. CASE WHEN 表达式有两种形式 --简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ...
- LinqToXml高级用法介绍
LinqToXml高级用法介绍 一.函数构造 什么是函数构造?其是指通过单个语句构建XML树的能力. 那么它有什么作用呢? 作用1.用单个表达式快速创建复杂的XML树 见实例代码CreateXml( ...
- Oracle学习笔记_06_CASE WHEN 用法介绍
1. CASE WHEN 表达式有两种形式 --简单Case函数 CASE sex ' THEN '男' ' THEN '女' ELSE '其他' END --Case搜索函数 CASE ' THEN ...
- mysql进阶(六)模糊查询的四种用法介绍
mysql中模糊查询的四种用法介绍 这篇文章主要介绍了mysql中模糊查询的四种用法,需要的朋友可以参考下. 下面介绍mysql中模糊查询的四种用法: 1 %: 表示任意0个或多个字符.可匹配任意类型 ...
- object-fit 属性的用法介绍
这个要在宽,高都是100%的情况下才能提现 object-fit 属性的用法介绍 fill(不保持纵横比缩放图片,使图片完全适应) contain(保持纵横比缩放图片,使图片的长边能完全显示出来) c ...
随机推荐
- linux系统使用grep命令提取文件的基名或者路径名
效果等于~]#dirname /etc/sysconfig/network-scripts/ifcfg-ens33 echo "/etc/sysconfig/network-scripts/ ...
- 自学Python-基于tcp协议的socket
自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...
- 牛客练习赛47 E DongDong数颜色 (树上启发式合并)
链接:https://ac.nowcoder.com/acm/contest/904/E 来源:牛客网 DongDong数颜色 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 5242 ...
- java8学习之Stream源码分析
上一次已经将Collectors类中的各种系统收集器的源代码进行了完整的学习,而在之前咱们已经花了大量的篇幅对其Stream进行了详细的示例学习,如: 那接下来则通过源代码的角度来对Stream的运作 ...
- BZOJ1787 [Ahoi2008]Meet 紧急集合[结论题]
location. 求到树上三点距离和最短的点及此距离. 这个不还是分类讨论题么,分两类大情况,如下图. 于是乎发现三个点对的lca中较深的那个lca是答案点.距离就是两两点对距离加起来除以2即可.这 ...
- ln: /usr/bin/mysql: Operation not permitted
一.背景 前段时间装mysql,就遇到了ln: /usr/bin/mysql: Operation not permitted的错误,网上好多方法都过时了,下边是我的解决方法 执行 sudo ln - ...
- 使用Nginx的proxy_cache缓存功能取代Squid[原创]
使用Nginx的proxy_cache缓存功能取代Squid[原创] [文章作者:张宴 本文版本:v1.2 最后修改:2009.01.12 转载请注明原文链接:http://blog.zyan.cc/ ...
- 京东POP店铺使用京东物流,如何拦截订单
先进入物流工作台:https://wl.jdwl.com/ 然后操作中心-销售订单查询 然后点击展开按钮 粘贴要查询的订单号 勾选订单,点击取消按钮
- JS实现表单全选以及取消全选实例
实现效果: 全选按钮:点击全选按钮所有的小按钮都会被选中:点掉全选按钮,所有按钮取消选中: 小按钮:只有全部被选中,全选按钮才会被选中 思路分析: 1.全选和取消全选做法:让下面所有复选框的 chec ...
- HTML+CSS之光标悬停图片翻转效果
设计思路: 首先做一个包括图片和说明文字的简单的页面结构,然后再设置它的变换.将变换的元素,即照片和文字放在一个父容器里面,这就需要四个父容器 ,再将这四个父容器放在最外层的舞台上面进 ...