这是根据尚硅谷最新的阳哥讲的JUC视频学习过程中总结的笔记,不得不说,阳哥的视频质量是真的高,从老版JUC和大厂面试班中刚开始看时就彻底爱上了这个一直给你鸡汤还时不时开车讲段子的老师,技术上刨析很清晰,在Java进阶阶段我以后肯定也会经常看阳哥的视频,来这里呢就是也想给大家分享一下自己学习到的东西,共同成长进步。
视频链接地址如下:
link
JUC是什么
java.util.concurrent在并发编程中使用的工具包 对JUC知识的高阶内容讲解和实战增强
本课程学生对象(非零基础)
了解Java技术栈,实际一线编码工作过1~5年的Java开发工程师,热爱高并发技术的小伙伴也同样欢迎
本课程难度对标
阿里P6、P7对高级Java开发工程师的要求明细 —— 阿里手册规范
前置知识
IDEA开发工具和常用快捷键自定义配置
IDEA之lombok插件
Java8新特性 —— Java8语法本身+函数式编程+方法引用+lambda表达式
JUC初级篇
JVM —— JVM体系结构
参考书籍 —— 《深入理解JVM虚拟机》
本次讲解采用的Java版本
java8
硬件方面
摩尔定律失效
摩尔定律:它是由因特尔创始人之一Gordon Moore(戈登·摩尔)提出来的,其内容为:
当价格不变时,集成电路上可容纳的元器件的数目且约每隔18-24个月便会增加一倍,性能也将提升一倍。
换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。这一定律揭示了信息技术进步的速度。可是从2003年开始CPU主频已经不再翻倍,而是采用多核而不是更快的主频
在主频不再提高且核数在不断增加的情况下,要想让程序更快就要用到并行或并发编程
软件方面
面试B格可以高一点点
充分利用多核处理器
提高程序性能,高并发系统
提高程序吞吐量,异步+回调等生产需求
弊端及问题
程序安全性问题:i++ 集合类安全否
线程锁问题
线程性能问题
Java线程理解以及openjdk中的实现
更加底层的C++源码解读
thread.c
java线程是通过start的方法启动执行的,主要内容在native方法start0中,
openjdk的写JNI一般是一一对应的,Thread.java对应的就是Thread.c
start0其实就是JVM_StartThread。此时查看源代码可以看到在jvm.h中找到了声明,jvm.cpp中有实现
jvm.cpp
thread.cpp
1把锁:synchronized
2个并:
并发(concurrent):是在同一实体上的多个事件,是在一台处理器上"同时"处理多个任务。同一时刻,其实是只有一个事件在发生 (秒杀和抢票)
并行(parallel):是在不同实体上的多个事件,是在多台处理器上同时处理多个任务。同一时刻,大家真的都在做事情,你做你的,我做我的,但是我们都在做 (泡方便面)
3个程
进程:简单的说,在系统中运行的一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源
线程:也被称为轻量级进程,在同一个进程内会有1个或多个进程,是大多数操作系统进行时序调度的基本单元
管程:Monitor(监视器),也就是我们平时所说的锁
Monitor其实是一种同步机制,她的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码
JVM中同步是基于进入和退出监视器对象(Monitor,管程对象)来实现的,每个对象实例都会有一个Monitor对象
Object o = new Object(); new Thread(() -> { synchronized(o){ } },"t2").start();
Monitor对象会和Java对象一同创建并销毁,它底层是由C++语言来实现的
JVM第3版:执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是否正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程
Java线程分为用户线程和守护线程
一般情况下不做特别说明配置,默认都是用户线程
用户线程(User Thread):是系统的工作线程,它会完成这个程序需要完成的业务操作
守护线程(Daemon Thread)
是一种特殊的线程为其他线程服务的,在后台默默地完成一些系统性的服务,比如垃圾回收线程就是最典型的例子
守护线程作为一个服务线程,没有服务对象就没有必要继续运行了,如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以假如当系统只剩下守护线程的时候,java虚拟机会自动退出
线程daemon属性
//源码解读
public final boolean isDaemon(){
return daemon;
}
true表示是守护线程
false表示是用户线程
code演示
public class DaemonDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 开始运行, " +
(Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
while (true) {
}
}, "t1");
t1.setDaemon(true);
t1.start();
//暂停几秒钟线程
try{ TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + "\t ----end 主线程");
}
}
小总结
如果用户线程全部结束意味着程序需要完成的业务操作已经结束了,守护线程随着JVM一同结束工作
setDaemon(true)方法必须在start()之前设置,否则报IllegalThreadStateException异常
你不能把正在运行的常规线程设置为守护线程
//This method must be invoked before the thread is started
public final void setDaemon(boolean on){
checkAccess();
if(isAlive()){
throw new IllegalThreadStateException();
}
daemon = on;
}
Future接口(FutureTask实现类)定义了操作 异步任务 执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,忙其它事情或者先执行完,过了一会儿才去获取子任务的执行结果或变更的任务状态。(举例上课买水)
一句话:Future接口可以为主线程开一个分支任务,专门为主线程处理耗时和费力的复杂业务
Future是Java5新加的一个接口,它提供了一种异步并行计算的功能。
如果主线程需要执行一个很耗时的计算任务,我们就可以通过future把这个任务放到异步线程中执行。主线程继续处理其他任务或者先行结束,再通过Future获取计算结果。
代码说话:
Runnable接口
Callable接口
Future接口和FutureTask实现类
目的:异步多线程任务执行且返回有结果,三个特点:多线程/有返回/异步任务
(班长为老师去买水作为新启动的异步多线程任务且买到水有结果返回)
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new MyThread());
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(futureTask.get());
}
}
class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("----come in");
return "hello Callable";
}
}
//优点:future+线程池异步多线程任务配合,能显著提高程序的执行效率
//
/**
* @author William
* @create 2022-06-05 16:59
*/
public class FutureThreadPoolDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3个任务,目前只有一个线程main来处理,请问耗时多少?
ExecutorService threadPool = Executors.newFixedThreadPool(3);
long startTime = System.currentTimeMillis();
FutureTask<String> futureTask1 = new FutureTask<String>(() -> {
try{ TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
return "task1 over";
});
threadPool.submit(futureTask1);
FutureTask<String> futureTask2 = new FutureTask<String>(() -> {
try{ TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
return "task2 over";
});
threadPool.submit(futureTask2);
System.out.println(futureTask1.get());
System.out.println(futureTask2.get());
try{ TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
long endTime = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime - startTime) + "毫秒");
System.out.println(Thread.currentThread().getName() + "\t ------end");
threadPool.shutdown();
}
public static void m1(){
long startTime = System.currentTimeMillis();
//暂停毫秒
try{ TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
try{ TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
try{ TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
long endTime = System.currentTimeMillis();
System.out.println("-----costTime: " + (endTime - startTime) + " 毫秒");
System.out.println(Thread.currentThread().getName() + "\t ------end");
}
}
Future编码实战和优缺点分析
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask<String> futureTask = new FutureTask<String>(() -> {
System.out.println(Thread.currentThread().getName() + "\t ----come in");
//暂停几秒钟线程
try{ TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
return "task over";
});
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(Thread.currentThread().getName() + "\t ----忙其它任务了");
//System.out.println(futureTask.get());
//System.out.println(futureTask.get(3, TimeUnit.SECONDS));
while(true){
if(futureTask.isDone()){
System.out.println(futureTask.get());
break;
}else{
//暂停毫秒
try{ TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("正在处理中,不要再催了,越催越慢,再催熄火");
}
}
}
}
/**
* get()阻塞
* 1 容易导致阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,程序容易阻塞
* 2 假如我不愿意等待很长时间,我希望过时不候,可以自动离开
*
* isDone() 轮询
* 轮询的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果。如果想要异步获取结果,通常都会以轮询的方式去
* 获取结果,尽量不要阻塞
*
* 结论:
* Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果
*/
想完成一些复杂的功能:
CompletableFuture为什么出现?
get()方法在Future计算完成之前会一直处在阻塞状态下,isDone()方法容易耗费CPU资源,对于真正的异步处理我们希望是可以通过传入回调函数,在Future结束时自动调用该回调函数,这样,我们就不用等待结果
阻塞的方式和异步编程的设计理念相违背,而轮询的方式会耗费无谓的CPU资源。因此,JDK8设计出CompletableFuture
CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方
CompletableFuture和CompletionStage源码分别介绍
//类架构说明
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>{}
接口CompletionStage是什么?
代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段,有些类似Linux系统的管道分隔符传参数
类CompletableFuture是什么?
核心的四个静态方法,来创建一个异步任务
runAsync 无 返回值
public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture runAsync(Runnable runnable, Executor executor)
supplyAsync 有 返回值
public static CompletableFuture supplyAsync(Supplier supplier)
public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)
上述Executor executor参数说明:没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool()作为它的线程池执行异步代码
如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码
Code
无 返回值
有 返回值
Code之 通用演示,减少阻塞和轮询:从Java8开始引入CompletableFuture,它是Future的功能增强版,减少阻塞和轮询,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法
/**
* @author William
* @create 2022-07-02 11:44
*/
public class CompletableFutureUseDemo {
//解释下为什么默认线程池关闭,自定义线程池记得关闭
public static void main(String[] args) throws ExecutionException, InterruptedException {
//通过自定义线程池 规避下面那个主线程立刻结束导致守护线程fork join迅速结束收不到结果的问题
ExecutorService threadPool = Executors.newFixedThreadPool(3);
try{
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt();
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("1秒种后出结果:" + result);
if(result > 5){
int i = 10/0;
}
return result;
}, threadPool).whenComplete((v, e) -> {
if(e == null){
System.out.println("----计算完成,更新系统UpdateValue:"+v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况:" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其他任务");
}catch(Exception e){
e.printStackTrace();
}finally{
threadPool.shutdown();
}
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭;暂停3秒钟线程
//try{ TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
}
private static void future1() throws InterruptedException, ExecutionException {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("1秒种后出结果:" + result);
return result;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其他任务");
System.out.println(completableFuture.get());
}
}
CompletableFuture的优点:
函数式编程已经主流
大厂面试题看看
- 你怎么理解java多线程的?怎么处理并发?线程池有哪几个核心参数?
- Java加锁有哪几种锁?我先说了syn,syn刚讲到偏向锁,他就不让我讲了,太自信了
- 简单说说lock?
- hashmap的实现原理?hash冲突怎么解决?为什么使用红黑树?
- spring里面使用了哪些设计模式?循环依赖怎么解决?
- 项目中哪个地方用到了countdownlanch,怎么使用的?
- JVM项目了解过吗?说说都有什么?栈里面都放什么东西?
- 都用redis来做什么?aof和rdb都是什么做持久化缓存的?
- mysql的锁机制?mysql的索引是怎么实现的?
- spring实现事务的几种方式?
- zookeeper怎么实现分布式锁?
- java8函数式编程用过吗?
- 算法:求链表倒数第K个元素
Lambda表达式+Stream流式调用+Chain链式调用+Java8函数式编程
Runnable
Runnable我们已经说过无数次了,无参数,无返回值
@FunctionalInterface
public interface Runnable{
public abstract void run();
}
Function
Function
接受一个参数,并且有返回值 @FunctionalInterface
public interface Functional
{ R apply(T, t);
}
Consumer
Comsumer接受一个参数,没有返回值
@FunctionalInterface
public interface Consumer{
void accept(T t);
}
BiConsumer
接受两个参数,没有返回值 @FunctionalInterface
public interface BiConsumer
{ void accept(T t, U u);
}
Suppiler
Supplier没有参数,有一个返回值
@FunctionalInterface
public interface Supplier{
T get();
}
先说说join和get对比
/**
* @author William
* @create 2022-07-02 17:10
*/
public class CompletableFutureMallDemo {
public static void main(String[] args) {
/*Student student = new Student();
student.setId(1);
student.setStudentName("z3");
student.setMajor("cs");
student.setId(12).setStudentName("li4").setMajor("history");*/
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
return "hello 1234";
});
//get()会有受检时异常 join()无 其他地方它俩基本一样
//System.out.println(completableFuture.get());
System.out.println(completableFuture.join());
}
}
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
class Student{
private Integer id;
private String studentName;
private String major;
}
说说你过去工作中的项目亮点?
大厂业务需求说明
切记,功能 -> 性能
电商网站比价需求分析
/**
* 1. 需求说明
* 1. 同一款产品,同时搜索出同款产品在各大电商平台的售价
* 2. 同一款产品,同时搜索出本产品在同一个电商平台下,各个入驻卖家售价是多少
* 2. 输出返回
* 出来希望时同款产品在不同地方的加个清单列表,返回一个List
* 《mysql》 in jd price is 88.05
* 《mysql》 in dangdang price us 86.11
* 《mysql》 in taobao price is 90.43
* 3. 解决方案,比对同一个商品在各个平台上的价格,要求获得一个清单列表
* 1. step by step,按部就班,查完京东查淘宝,查完淘宝查天猫....
* 2. all in 万箭齐发,一口气多线程异步任务同时查询....
* @author William
* @create 2022-07-02 17:10
*/
public class CompletableFutureMallDemo {
static List<NetMall> list = Arrays.asList(
new NetMall("jd"),
new NetMall("dangdang"),
new NetMall("taobao")
);
/**
* step by step 一家一家查
* List ----> map ----> List
*@Param [list, productName]
*@Return
*/
public static List<String> getPrice(List<NetMall> list, String productName){
//《mysql》 in taobao price is 90.43
return list
.stream()
.map(netMall ->
String.format(productName + "in %s price is %.2f",//%s是占位符
netMall.getNetMallName(),
netMall.calcPrice(productName)))
.collect(Collectors.toList());
}
/**
* List ----> List> ----> List
*@Param [list, productName]
*@Return
*/
public static List<String> getPriceByCompletableFuture(List<NetMall> list, String productName){
return list.stream().map(netMall -> CompletableFuture.supplyAsync(() -> String.format(productName + "in %s price is %.2f",//%s是占位符
netMall.getNetMallName(),
netMall.calcPrice(productName))))
.collect(Collectors.toList())
.stream().map(s -> s.join())
.collect(Collectors.toList());
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
List<String> list1 = getPrice(list, "mysql");
for (String element : list1){
System.out.println(element);
}
long endTime = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime - startTime) + "毫秒");
/* mysqlin jd price is 110.26 mysqlin dangdang price is 110.27 mysqlin taobao price is 109.32
----costTime: 3148毫秒
*/
System.out.println("----------------------");
long startTime2 = System.currentTimeMillis();
List<String> list2 = getPriceByCompletableFuture(list, "mysql");
for (String element : list2){
System.out.println(element);
}//mysqlin jd price is 110.3 mysqlin dangdang price is 110.4 mysqlin taobao price is 110.77
//----costTime: 1030毫秒
long endTime2 = System.currentTimeMillis();
System.out.println("----costTime: " + (endTime2 - startTime2) + "毫秒");
}
}
class NetMall{
@Getter
private String netMallName;
public NetMall(String netMallName){
this.netMallName = netMallName;
}
public double calcPrice(String productName){//更严谨的话用BigDecimal
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
}
}
获得结果和触发计算
获取结果
public T get() 不见不散
public T get(long timeout, TimeUnit unit) 过时不候
public T join() 给我就输出结果 不给报Timeout错
public T getNow(T valueIfAbsent) 没有计算完成的情况下,给我一个替代的结果;立即获取结果不阻塞:计算完,返回计算完成后的结果;没算完,返回设定的valueIfAbsent值
主动触发计算
public boolean complete(T value) 是否打断get方法立即返回括号值
public class CompletableFutureAPIDemo {
public static void main(String[] args) {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "abc";
});
//System.out.println(completableFuture.get());
//System.out.println(completableFuture.getNow());
//System.out.println(completableFuture.join());
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
//System.out.println(completableFuture.getNow("xxx"));
System.out.println(completableFuture.complete("completeValue"+"\t"+completableFuture.join()));
}
}
对计算结果进行处理
thenApply handle 计算结果存在依赖关系,这两个线程串行化
异常相关:
thenApply:由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
handle:有异常也可以往下一步走,根据带的异常参数可以进一步处理
/**
* @author William
* @create 2022-07-03 14:19
*/
public class CompletableFutureAPI2Demo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("111");
return 1;
},threadPool).handle((f, e) -> {
int i = 10/0;
System.out.println("222");
return f + 2;
}).handle((f, e) -> {
System.out.println("333");
return f + 3;
}).whenComplete((v,e) -> {
if(e == null){
System.out.println("----计算结果:"+v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println(e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "----主线程先去忙其他任务");
threadPool.shutdown();
//主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭
//try{ TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
对计算结果进行消费
接收任务的处理结果,并消费处理,无返回结果
thenAccept
对比补充 Code之任务之间的顺序执行
- thenRun(Runnable runnable):任务A执行完执行B,并且B不需要A的结果
- thenAccept(Consumer action):任务A执行完执行B,B需要A的结果,但是任务B无返回值
- thenApply(Function fn):任务A执行完致性B,B需要A的结果,同时任务B有返回值
public class CompletableFutureAPI3Demo { public static void main(String[] args) { /*CompletableFuture.supplyAsync(() -> { return 1; }).thenApply(f -> { return f + 2; }).thenApply(f -> { return f + 3; // }).thenAccept(r -> { // System.out.println(r); }).thenAccept(System.out::println);*/ System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());//null System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(r ->System.out.println(r)).join());//resultA null System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(r -> r + "resultB").join());//resultAresultB } }
CompletableFuture和线程池说明
以thenRun和thenRunAsync为例,有什么区别?
- 没有传入自定义线程池,都用默认线程池ForkJoinPool
- 传入了一个自定义线程池,如果你执行第一个任务的时候,传入了一个自定义线程池:
- 调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是公用一个线程池
- 调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入线程池,第二个使用的是ForkJoin线程池(另起炉灶)
- 备注:有可能处理太快,系统优化切换原则,直接使用main线程处理
其他如:thenAccept和thenAcceptAsync,thenApply和thenApplyAsync等,它们之间的区别也是同理
对计算速度进行选用
谁快用谁 applyToEither
public class CompletableFutureFastDemo { public static void main(String[] args) { CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> { System.out.println("A come in"); try{ TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return "playA"; }); CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> { System.out.println("B come in"); try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "playB"; }); CompletableFuture<String> result = playA.applyToEither(playB, f -> { return f + " is winer"; }); System.out.println(Thread.currentThread().getName() + "\t"+"-----: "+result.join()); } }
对计算结果进行合并
两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine来处理,先完成的先等着,等待其他分支任务
thenCombine
/**
* @author William
* @create 2022-07-03 16:15
*/
public class CompletableFutureCombineDemo {
public static void main(String[] args) {
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() ->{
System.out.println(Thread.currentThread().getName() + "\t ---启动");
//暂停几秒钟线程
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() ->{
System.out.println(Thread.currentThread().getName() + "\t ---启动");
//暂停几秒钟线程
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 20;
});
CompletableFuture<Integer> result = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
System.out.println("开始两个结果合并");
return x + y;
});
System.out.println(result.join());
}
}