CompletableFuture教程


前言

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 可以写在中间,最后,等任意位置,代表着处理异常


总结

下面这张图是我自己学习的时候的一些总结,希望能对读者有一些帮助。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值