前言
java程序员绕不开的就是高并发。而高并发系列中,无非就是异步、锁、多线程。今天要介绍的就是CompletableFuture。本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!
一、基础篇
1、案例1_ CompletableFuture.supplyAsync()
1.1、需求
有三步骤,(名字相同的是同一个线程。小白是一个线程,厨师是一个线程):
1、小白点菜
2、厨师做菜
3、小白吃饭
1.2、代码
package com.zheng.sync;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/04/26 21:59
* @desc: CompletableFuture 基础篇_1
* 1、小白点菜
* 2、厨师做菜
* 3、小白吃饭
*
*
*/
public class CompletableFutureBasicOne {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白进入餐厅");
SmallUtil.printTimeAndThread("小白点了 番茄炒蛋 + 米饭");
SmallUtil.printTimeAndThread("小白再打王者1");
// jdk8的异步
CompletableFuture<String > cf1 = CompletableFuture.supplyAsync(()->{
SmallUtil.printTimeAndThread("厨师开始炒菜了");
SmallUtil.sleepMillis(1000L);
SmallUtil.printTimeAndThread("厨师开始打饭了");
SmallUtil.sleepMillis(1000L);
return "番茄炒蛋 + 米饭 做好了";
});
SmallUtil.printTimeAndThread("小白再打王者2");
/**
* cf1.join() 的结果集,就是 CompletableFuture的泛型的值,
* cf1.join() 也会抛出异常
*/
SmallUtil.printTimeAndThread(String.format("%s,小白开吃了",cf1.join()));
/**
* 结果:
* 2022-04-26 10:04:26 | 1 | main | 小白进入餐厅
* 2022-04-26 10:04:26 | 1 | main | 小白点了 番茄炒蛋 + 米饭
* 2022-04-26 10:04:26 | 1 | main | 小白再打王者1
* 2022-04-26 10:04:26 | 1 | main | 小白再打王者2
* 2022-04-26 10:04:26 | 12 | ForkJoinPool.commonPool-worker-9 | 厨师开始炒菜了
* 2022-04-26 10:04:27 | 12 | ForkJoinPool.commonPool-worker-9 | 厨师开始打饭了
* 2022-04-26 10:04:28 | 1 | main | 番茄炒蛋 + 米饭 做好了,小白开吃了
*/
}
}
1.3、总结
CompletableFuture.supplyAsync(() -> {return “”;})。supplyAsync 是支持返回值的异步;runAsync 不支持返回值的异步。
2、案例2_ CompletableFuture.thenCompose()
2.1、需求
1、小白点餐
2、厨师做饭
3、服务器送菜(这个需要在2的后面执行)
4、小白吃饭
2.2、代码
package com.zheng.sync;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/04/26 22:32
* @desc: CompletableFuture 基础篇_2
* 1、小白点餐
* 2、厨师做饭
* 3、服务器送菜(这个需要在2的后面执行)
* 4、小白吃饭
*/
public class CompletableFutureBasicTwo {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白进入餐厅");
SmallUtil.printTimeAndThread("小白点了 番茄炒蛋 + 米饭");
SmallUtil.printTimeAndThread("小白再打王者1");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("厨师开始炒菜了");
SmallUtil.sleepMillis(1000L);
return "番茄炒蛋";
}).thenCompose(dist -> CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("服务员开始打饭了");
SmallUtil.sleepMillis(1000L);
return dist + "米饭";
}));
/**
* thenCompose 这个方法中:是吧前面任务的结果,交给下一个任务
* 1、dist 代表着前面那个线程的返回值,这里是 番茄炒蛋(String)
* 2、 CompletableFuture.supplyAsync 代表着,里面的代码会在领一个线程中执行
* 3、前一个任务完成,有结果以后,下一个任务才会触发
*/
SmallUtil.printTimeAndThread("小白再打王者2");
SmallUtil.printTimeAndThread(String.format("%s,小白开吃了",cf1.join()));
/**
* 2022-04-26 10:04:17 | 1 | main | 小白进入餐厅
* 2022-04-26 10:04:17 | 1 | main | 小白点了 番茄炒蛋 + 米饭
* 2022-04-26 10:04:17 | 1 | main | 小白再打王者1
* 2022-04-26 10:04:17 | 12 | ForkJoinPool.commonPool-worker-9 | 厨师开始炒菜了
* 2022-04-26 10:04:17 | 1 | main | 小白再打王者2
* 2022-04-26 10:04:19 | 12 | ForkJoinPool.commonPool-worker-9 | 服务员开始打饭了
* 2022-04-26 10:04:20 | 1 | main | 番茄炒蛋米饭,小白开吃了
*/
}
}
2.3、总结
CompletableFuture.supplyAsync().thenCompose(); 这个thenCompose中的方法,是再第一个的后面执行的。
3、案例3_ CompletableFuture.thenCombine()
3.1、需求
1、小白点饭
2、厨师做饭
3、服务器蒸米饭 (2、3 是同事进行的,没有先后顺序)
4、小白吃饭
3.2、代码
package com.zheng.sync.basic;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/04/26 22:58
* @desc: CompletableFuture 基础篇_2
* 1、小白点饭
* 2、厨师做饭
* 3、服务器蒸米饭 (2、3 是同事进行的,没有先后顺序)
* 4、小白吃饭
*/
public class CompletableFutureBasicThree {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白进入餐厅");
SmallUtil.printTimeAndThread("小白点了 番茄炒蛋 + 米饭");
SmallUtil.printTimeAndThread("小白再打王者1");
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("厨师开始炒菜了");
SmallUtil.sleepMillis(1000L);
return "番茄炒蛋";
}).thenCombine(CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("服务员开始蒸米饭了");
SmallUtil.sleepMillis(1000L);
return "米饭";
}), (dish,rice) -> {
SmallUtil.printTimeAndThread("服务员开始打饭了");
SmallUtil.sleepMillis(1000L);
return String.format("%s + %s 好了啊" ,dish,rice);
} );
/**
* thenCombine 代表着,这俩异步任务是同时执行的,同时执行完了以后,再把他们加工成一个结果
*/
SmallUtil.printTimeAndThread("小白再打王者2");
SmallUtil.printTimeAndThread(String.format("%s,小白开吃了",cf1.join()));
/**
* 2022-04-26 11:04:36 | 1 | main | 小白进入餐厅
* 2022-04-26 11:04:36 | 1 | main | 小白点了 番茄炒蛋 + 米饭
* 2022-04-26 11:04:36 | 1 | main | 小白再打王者1
* 2022-04-26 11:04:36 | 12 | ForkJoinPool.commonPool-worker-9 | 厨师开始炒菜了
* 2022-04-26 11:04:36 | 13 | ForkJoinPool.commonPool-worker-2 | 服务员开始蒸米饭了
* 2022-04-26 11:04:36 | 1 | main | 小白再打王者2
* 2022-04-26 11:04:37 | 13 | ForkJoinPool.commonPool-worker-2 | 服务员开始打饭了
* 2022-04-26 11:04:38 | 1 | main | 番茄炒蛋 + 米饭 好了啊,小白开吃了
*/
}
}
3.3、总结
CompletableFuture.supplyAsync().thenCombine();这个thenCombine代表他们是同时执行的。
二、扩展篇
1、案例1_ CompletableFuture.thenApplyAsync()
1.1、需求
1、小白吃好了
2、小白结账 要发票
3、小白接到朋友电话,约定了一起打游戏
4、服务员收款
5、收银员开发票(注意,和上面的4,不是一个人)
6、小白收到发票,准备回家
1.2、代码
package com.zheng.sync.advance;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/04/27 22:50
* @desc: 另一种实现方式
* 1、小白吃好了
* 2、小白结账 要发票
* 3、小白接到朋友电话,约定了一起打游戏
* 4、服务员收款
* 5、收银员开发票(注意,和上面的4,不是一个人)
* 6、小白收到发票,准备回家
*/
public class CompletableFutureAdvanceOne_2 {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白吃好了");
SmallUtil.printTimeAndThread("小白结账 要发票");
// CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() ->{
// SmallUtil.printTimeAndThread("服务员收款");
// SmallUtil.sleepMillis(1000L);
// return "服务员收款";
// }).thenApplyAsync(dist -> {
// SmallUtil.printTimeAndThread("收银员开发票");
// SmallUtil.sleepMillis(1000L);
// return "收银员开发票";
// } );
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("服务员收款 500元");
SmallUtil.sleepMillis(1000L);
return "500";
}).thenApplyAsync(money -> {
SmallUtil.printTimeAndThread(String.format("收银员开发票 %s" ,money));
SmallUtil.sleepMillis(1000L);
return String.format("收银员开发票 %s" ,money);
});
SmallUtil.printTimeAndThread("小白接到朋友电话,约定了一起打游戏");
SmallUtil.printTimeAndThread(String.format("小白收到%s,准备回家",cf1.join()));
/**
* "C:\Program Files\Java\jdk1.8.0_161\bin\java.exe" -javaagent:D:\java\ruanjian\idea\path\lib\idea_rt.jar=53062:D:\java\ruanjian\idea\path\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_161\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\rt.jar;D:\java\ruanjian\idea\file\testcompletablefuture\target\classes;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-web\2.6.7\spring-boot-starter-web-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter\2.6.7\spring-boot-starter-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot\2.6.7\spring-boot-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-autoconfigure\2.6.7\spring-boot-autoconfigure-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-logging\2.6.7\spring-boot-starter-logging-2.6.7.jar;D:\java\ruanjian\maven\cangku\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\java\ruanjian\maven\cangku\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\java\ruanjian\maven\cangku\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\java\ruanjian\maven\cangku\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\java\ruanjian\maven\cangku\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\java\ruanjian\maven\cangku\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\java\ruanjian\maven\cangku\org\yaml\snakeyaml\1.29\snakeyaml-1.29.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-json\2.6.7\spring-boot-starter-json-2.6.7.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-databind\2.13.2.1\jackson-databind-2.13.2.1.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-annotations\2.13.2\jackson-annotations-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-core\2.13.2\jackson-core-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.2\jackson-datatype-jdk8-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.2\jackson-datatype-jsr310-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.2\jackson-module-parameter-names-2.13.2.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-tomcat\2.6.7\spring-boot-starter-tomcat-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-core\9.0.62\tomcat-embed-core-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-el\9.0.62\tomcat-embed-el-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.62\tomcat-embed-websocket-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-web\5.3.19\spring-web-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-beans\5.3.19\spring-beans-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-webmvc\5.3.19\spring-webmvc-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-aop\5.3.19\spring-aop-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-context\5.3.19\spring-context-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-expression\5.3.19\spring-expression-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;D:\java\ruanjian\maven\cangku\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-core\5.3.19\spring-core-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-jcl\5.3.19\spring-jcl-5.3.19.jar" com.zheng.sync.advance.CompletableFutureAdvanceOne_2
* 2022-05-04 10:05:16 | 1 | main | 小白吃好了
* 2022-05-04 10:05:16 | 1 | main | 小白结账 要发票
* 2022-05-04 10:05:16 | 12 | ForkJoinPool.commonPool-worker-9 | 服务员收款 500元
* 2022-05-04 10:05:16 | 1 | main | 小白接到朋友电话,约定了一起打游戏
* 2022-05-04 10:05:17 | 12 | ForkJoinPool.commonPool-worker-9 | 收银员开发票 500
* 2022-05-04 10:05:18 | 1 | main | 小白收到收银员开发票 500,准备回家
*/
}
}
1.3、总结
CompletableFuture.supplyAsync() .thenApplyAsync();这个thenApplyAsync虽然有先后顺序,但是是俩个线程。
2、案例2_ CompletableFuture.applyToEither()
2.1、需求
1、小白吃完了,准备回家
2、小白在等车,哪个车先来,就做哪个车
2.2、代码
package com.zheng.sync.advance;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/04/28 23:03
* @desc: CompletableFuture扩展_2
* 1、小白吃完了,准备回家
* 2、小白在等车,哪个车先来,就做哪个车
*
* todo: .applyToEither() 俩线程,谁先执行完,就把先执行完的结果返回给Future
*/
public class CompletableFutureAdvanceTwo {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白吃完了,准备回家");
SmallUtil.printTimeAndThread("小白在等车");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("70路公交来了");
SmallUtil.sleepMillis(3000L);
return "70路公交";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("80路公交来了");
SmallUtil.sleepMillis(2000L);
return "80路公交";
}),firstComeBus -> firstComeBus);
/**
* 2022-04-28 11:04:04 | 1 | main | 小白吃完了,准备回家
* 2022-04-28 11:04:04 | 1 | main | 小白在等车
* 2022-04-28 11:04:04 | 12 | ForkJoinPool.commonPool-worker-9 | 70路公交来了
* 2022-04-28 11:04:04 | 13 | ForkJoinPool.commonPool-worker-2 | 80路公交来了
* 2022-04-28 11:04:06 | 1 | main | 小白坐上了 80路公交
*/
SmallUtil.printTimeAndThread(String.format("小白坐上了 %s ",cf1.join()));
}
}
2.3、总结
CompletableFuture.supplyAsync().applyToEither(); 中的applyToEither 代表着谁先来,就先执行谁
3、案例3_ CompletableFuture.exceptionally()
3.1、需求
1、小白吃完了,准备回家
2、小白在等车,哪个车先来,就做哪个车
3、假设小白做的是700路公交,然后700路公交路上没电了,然后小白打车回家
3.2、代码
3.2.1、没处理异常的代码:
package com.zheng.sync.advance;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/05/04 9:45
* @desc: 这个主要是处理,CompletableFutureAdvance 的异常处理
* 1、小白吃完了,准备回家
* 2、小白在等车,哪个车先来,就做哪个车
* 3、假设小白做的是700路公交,然后700路公交路上没电了,然后小白打车回家
*/
public class CompletableFutureAdvanceThree {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白吃完了,准备回家");
SmallUtil.printTimeAndThread("小白在等车");
CompletableFuture<String> bus = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("700路公交来了");
SmallUtil.sleepMillis(1000L);
return "700路公交";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("800路公交来了");
SmallUtil.sleepMillis(2000L);
return "800路公交";
}),firstComeBus -> {
SmallUtil.printTimeAndThread("小白坐上了"+firstComeBus);
if (firstComeBus.startsWith("700")){
throw new RuntimeException("700路公交没电了");
}
return firstComeBus;
});
/**
* 抛出一下异常:
* Exception in thread "main" java.util.concurrent.CompletionException: java.lang.RuntimeException: 700路公交没电了
* Caused by: java.lang.RuntimeException: 700路公交没电了
* at com.zheng.sync.advance.CompletableFutureAdvanceThree.lambda$main$2(CompletableFutureAdvanceThree.java:32)
*/
SmallUtil.printTimeAndThread(String.format("%s,小白做车回家",bus.join()));
}
}
3.2.2、处理了异常的代码:
package com.zheng.sync.advance;
import com.zheng.util.SmallUtil;
import java.util.concurrent.CompletableFuture;
/**
* @author: ZhengTianLiang
* @date: 2022/05/04 9:45
* @desc: 这个主要是处理,CompletableFutureAdvance 的异常处理
* 1、小白吃完了,准备回家
* 2、小白在等车,哪个车先来,就做哪个车
* 3、假设小白做的是700路公交,然后700路公交路上没电了,然后小白打车回家
* todo: 是为了处理,前面抛出的异常
*/
public class CompletableFutureAdvanceThree_2 {
public static void main(String[] args) {
SmallUtil.printTimeAndThread("小白吃完了,准备回家");
SmallUtil.printTimeAndThread("小白在等车");
CompletableFuture<String> bus = CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("700路公交来了");
SmallUtil.sleepMillis(1000L);
return "700路公交";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
SmallUtil.printTimeAndThread("800路公交来了");
SmallUtil.sleepMillis(2000L);
return "800路公交";
}),firstComeBus -> {
SmallUtil.printTimeAndThread("小白坐上了"+firstComeBus);
if (firstComeBus.startsWith("700")){
throw new RuntimeException("700路公交没电了");
}
return firstComeBus;
}).exceptionally(e -> {
SmallUtil.printTimeAndThread("进去了异常的方法"+e.getMessage());
return "做了出租车";
});
/**
* "C:\Program Files\Java\jdk1.8.0_161\bin\java.exe" -javaagent:D:\java\ruanjian\idea\path\lib\idea_rt.jar=50710:D:\java\ruanjian\idea\path\bin -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_161\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\rt.jar;D:\java\ruanjian\idea\file\testcompletablefuture\target\classes;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-web\2.6.7\spring-boot-starter-web-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter\2.6.7\spring-boot-starter-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot\2.6.7\spring-boot-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-autoconfigure\2.6.7\spring-boot-autoconfigure-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-logging\2.6.7\spring-boot-starter-logging-2.6.7.jar;D:\java\ruanjian\maven\cangku\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\java\ruanjian\maven\cangku\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\java\ruanjian\maven\cangku\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\java\ruanjian\maven\cangku\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\java\ruanjian\maven\cangku\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\java\ruanjian\maven\cangku\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\java\ruanjian\maven\cangku\org\yaml\snakeyaml\1.29\snakeyaml-1.29.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-json\2.6.7\spring-boot-starter-json-2.6.7.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-databind\2.13.2.1\jackson-databind-2.13.2.1.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-annotations\2.13.2\jackson-annotations-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\core\jackson-core\2.13.2\jackson-core-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.2\jackson-datatype-jdk8-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.2\jackson-datatype-jsr310-2.13.2.jar;D:\java\ruanjian\maven\cangku\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.2\jackson-module-parameter-names-2.13.2.jar;D:\java\ruanjian\maven\cangku\org\springframework\boot\spring-boot-starter-tomcat\2.6.7\spring-boot-starter-tomcat-2.6.7.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-core\9.0.62\tomcat-embed-core-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-el\9.0.62\tomcat-embed-el-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.62\tomcat-embed-websocket-9.0.62.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-web\5.3.19\spring-web-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-beans\5.3.19\spring-beans-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-webmvc\5.3.19\spring-webmvc-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-aop\5.3.19\spring-aop-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-context\5.3.19\spring-context-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-expression\5.3.19\spring-expression-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;D:\java\ruanjian\maven\cangku\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-core\5.3.19\spring-core-5.3.19.jar;D:\java\ruanjian\maven\cangku\org\springframework\spring-jcl\5.3.19\spring-jcl-5.3.19.jar" com.zheng.sync.advance.CompletableFutureAdvanceThree_2
* 2022-05-04 09:05:36 | 1 | main | 小白吃完了,准备回家
* 2022-05-04 09:05:36 | 1 | main | 小白在等车
* 2022-05-04 09:05:36 | 12 | ForkJoinPool.commonPool-worker-9 | 700路公交来了
* 2022-05-04 09:05:36 | 13 | ForkJoinPool.commonPool-worker-2 | 800路公交来了
* 2022-05-04 09:05:37 | 12 | ForkJoinPool.commonPool-worker-9 | 小白坐上了700路公交
* 2022-05-04 09:05:37 | 12 | ForkJoinPool.commonPool-worker-9 | 进去了异常的方法java.lang.RuntimeException: 700路公交没电了
* 2022-05-04 09:05:37 | 1 | main | 做了出租车,小白做车回家
*
* Process finished with exit code 0
*/
SmallUtil.printTimeAndThread(String.format("%s,小白做车回家",bus.join()));
}
}
3.3、总结
CompletableFuture bus = CompletableFuture.supplyAsync(() -> {return “700路公交”;})
.applyToEither(CompletableFuture.supplyAsync(() -> {return “800路公交”;}),
firstComeBus -> {throw new RuntimeException(“700路公交没电了”);}return firstComeBus;})
.exceptionally(e -> {return “做了出租车”;}); 其中,exceptionally 可以写在中间,最后,等任意位置,代表着处理异常
总结
下面这张图是我自己学习的时候的一些总结,希望能对读者有一些帮助。