CompletableFuture异步任务编排

使用jdk8中的java.util.concurrent.CompletableFuture非常方便进行异步任务编排

1.supplyAsync 开启异步任务

/**
 * 1.小白点菜
 * 2.厨师做菜
 * 3.小白吃饭
 */
public static void test1() {
    SmallTools.printTimeAndThread("小白进入餐厅");
    SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
    //启动一个线程执行厨师做饭
    CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
        SmallTools.printTimeAndThread("厨师炒菜");
        SmallTools.sleepMills(200);
        SmallTools.printTimeAndThread("厨师打饭");
        return "番茄炒蛋+一碗米饭 已经好了";
    });

    SmallTools.printTimeAndThread("小白在打王者");
    SmallTools.printTimeAndThread("小白开吃," + completableFuture.join());
}

2.主动计算
getNow有点特殊,如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值。不管线程任务是在运行还是结束了,如果在运行直接终止掉,只要执行了getNow后就会结束掉线程任务,如果没有获取到值就会使用默认值

join()与get()区别在于join()返回计算的结果或者抛出一个unchecked异常(CompletionException),而get()返回一个具体的异常.他们都会阻塞主线程,等待异步任务线程执行完。

get(): 会阻塞等待线程任务执行完毕,并且获取到返回值。 异常是checked异常,必须进行处理

 public static void test2() {
        SmallTools.printTimeAndThread("小白进入餐厅");
        SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
        //启动一个线程执行厨师做饭
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.sleepMills(200);
            SmallTools.printTimeAndThread("厨师炒菜");
            SmallTools.sleepMills(200);
            SmallTools.printTimeAndThread("厨师打饭");
            if(true){
                throw new RuntimeException("抛出异常测试");
            }
            return "番茄炒蛋+白米饭";
        });
        SmallTools.printTimeAndThread("小白在打王者");
        //getNow不管线程任务是在运行还是结束了,如果在运行直接终止掉,只要执行了getNow后就会结束掉线程任务,如果没有获取到值就会使用默认值
        try {
            SmallTools.printTimeAndThread("小白开吃," + completableFuture.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

join():会阻塞等待线程任务执行完毕,并且获取到返回值。 异常是unchecked异常

 public static void test2() {
        SmallTools.printTimeAndThread("小白进入餐厅");
        SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
        //启动一个线程执行厨师做饭
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.sleepMills(200);
            SmallTools.printTimeAndThread("厨师炒菜");
            SmallTools.sleepMills(200);
            SmallTools.printTimeAndThread("厨师打饭");
            if(true){
                throw new RuntimeException("抛出异常测试");
            }
            return "番茄炒蛋+白米饭";
        });
        SmallTools.printTimeAndThread("小白在打王者");
        SmallTools.printTimeAndThread("小白开吃," + completableFuture.join());
    }

getNow()

public static void test1() {
    SmallTools.printTimeAndThread("小白进入餐厅");
    SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
    //启动一个线程执行厨师做饭
    CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
        SmallTools.sleepMills(200);
        SmallTools.printTimeAndThread("厨师炒菜");
        SmallTools.sleepMills(200);
        SmallTools.printTimeAndThread("厨师打饭");
        return "番茄炒蛋+白米饭";
    });
    SmallTools.printTimeAndThread("小白在打王者");
    //getNow不管线程任务是在运行还是结束了,如果在运行直接终止掉,只要执行了getNow后就会结束掉线程任务,如果没有获取到值就会使用默认值
    SmallTools.printTimeAndThread("小白开吃," + completableFuture.getNow("默认值"));
}

如果使用 CompletableFuture.supplyAsync() 开启异步任务后,没有使用getNow join get方法,那么只要主线程结束,不管什么异步任务线程是否执行完,都不会等待他,会直接终止掉,同时主线程也执行结束
3.thenCompose
连接两个有依赖关系的异步任务,第一个线程执行完后会有一个返回值,然后传给第二个线程任务,第二个线程任务在开始执行

  /**
     * 1.小白点菜
     * 2.厨师炒菜
     * 小白打游戏
     * 3.等待厨师完成后,服务员在打饭
     * 4.小白开始吃
     */
    public static void test2() {
        SmallTools.printTimeAndThread("小白进入餐厅");
        SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
        //thenCompose的作用是    等待前一个任务结束后,有结果,下一个任务才会出发,
        //在这里就是必须要等待厨师炒菜完成后,服务员此才会打饭,服务员和厨师是不同的线程
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("厨师炒菜");
            SmallTools.sleepMills(200);
            return "番茄炒蛋";
        }).thenCompose(res -> CompletableFuture.supplyAsync(() -> {
                    SmallTools.printTimeAndThread("服务员打饭");
                    return res + "+米饭";
                })
        );

        SmallTools.printTimeAndThread("小白在打王者");
        SmallTools.printTimeAndThread("小白开吃," + completableFuture.join());
    }

4.thenCombine
合并两个没有依赖关系的异步任务的结果,两个异步线程任务同时启动,等待两个任务执行完成后,由BiFunction把两个异步任务执行的结果处理成一个结果在返回

/**
     * 厨师炒菜和服务员蒸饭在不同线程中同时开始了,任务都完成后就会汇集在一起
     */
    public static void test3() {
        SmallTools.printTimeAndThread("小白进入餐厅");
        SmallTools.printTimeAndThread("小白点了 番茄炒蛋+一碗米饭");
        //thenCombine的作用主要就是  把这两个任务一起执行,得到两个结果,再把这两个结果进行加工成一个结果
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("厨师炒菜");
            SmallTools.sleepMills(2000);
            return "番茄炒蛋";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("服务员蒸饭");
            SmallTools.sleepMills(2000);
            return "米饭";
        }), (r1, r2) -> r1 + r2);
        SmallTools.printTimeAndThread("小白在打王者");
        SmallTools.printTimeAndThread("小白开吃," + completableFuture.join());
    }

5.thenApply
1.thenApply 连接两个有依赖关系的任务,都是有同一个线程执行的
2.thenApplyAsync 连接两个有依赖关系的线程任务,由不同线程执行,但是由于使用线程池,会发生线程复用,所以打印出来的线程有的时候是同一个线程

他们与thenCompose的区别是,thenApply是同一个任务线程执行前后两个任务代码的,thenApplyAsync是两个不同线程执行的

//thenApply    
public static void test1() {
        SmallTools.printTimeAndThread("小白吃完了");
        //thenApply  这前后来两个任务都是同一个线程执行的,都是收银员执行
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("收银员收到小白的付款");
            SmallTools.sleepMills(200);
            return "200";
        }).thenApply((res) -> {
            SmallTools.printTimeAndThread("收银员开发票");
            SmallTools.sleepMills(200);
            return res + "元发票";
        });

        SmallTools.printTimeAndThread("小白接到一个电话想要一起打游戏");
        SmallTools.printTimeAndThread(String.format("小白拿到%s,准备回家", completableFuture.join()));
    }
//thenApplySync
    public static void test2() {
        SmallTools.printTimeAndThread("小白吃完了");
        //  两个线程任务执行
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("收银员收到小白的付款");
            SmallTools.sleepMills(200);
            return "200";
        }).thenApplyAsync((res) -> {
            SmallTools.printTimeAndThread("服务员开发票");
            SmallTools.sleepMills(200);
            return res + "元发票";
        });

        SmallTools.printTimeAndThread("小白接到一个电话想要一起打游戏");
        SmallTools.printTimeAndThread(String.format("小白拿到%s,准备回家", completableFuture.join()));
    }

6.applyToEitherAsync
那个任务先结束就把那个任务的结果交给function ,并且没有结束的那个任务会自动被结束掉

// applyToEitherAsync
public static void test3() {
        SmallTools.printTimeAndThread("小白走出餐厅,来到公交车站");
        //applyToEitherAsync 那个任务先结束就把那个任务的结果交给function ,并且没有结束的那个任务会自动被结束掉
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("700路公交车正在赶来");
            SmallTools.sleepMills(100);
            return "700";
        }).applyToEitherAsync(CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("800路公交车正在赶来");
            SmallTools.sleepMills(6000);
            SmallTools.printTimeAndThread("800路公交车正在赶来。。。。。。。。。");
            return "800";
        }), res -> res);

        SmallTools.printTimeAndThread(String.format("小白做%s路公交车回家", completableFuture.join()));
    }

7.exceptionally
捕获异常

public static void test5() {
        SmallTools.printTimeAndThread("小白走出餐厅,来到公交车站");
        SmallTools.printTimeAndThread("等待700路或者800路公交车来到公交车站");
        //
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
                    SmallTools.printTimeAndThread("700路公交车正在赶来");
                    SmallTools.sleepMills(100);
                    if(true){
                        throw new RuntimeException("700路公交撞树了");
                    }else {
                        return "700";
                    }
                }).exceptionally(e->{
                    return e.getMessage();
                })
                .applyToEitherAsync(CompletableFuture.supplyAsync(() -> {
                    SmallTools.printTimeAndThread("800路公交车正在赶来");
                    SmallTools.sleepMills(100);
                    SmallTools.printTimeAndThread("800路公交车正在赶来。。。。。。。。。");
                    return "800";
                }), res -> {
//                    if (res.equals("700")) {
//                        throw new RuntimeException("700路公交撞树了");
//                    }
                    return res;
                }).exceptionally(e -> {
                    SmallTools.printTimeAndThread(e.getMessage());
                    SmallTools.printTimeAndThread("小白叫了出租车");
                    return "出租车";
                });

        SmallTools.printTimeAndThread(String.format("小白做%s回家", completableFuture.join()));
    }

    public static void test4() {
        SmallTools.printTimeAndThread("小白走出餐厅,来到公交车站");
        SmallTools.printTimeAndThread("等待700路或者800路公交车来到公交车站");
        // exceptionally 捕获异常
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("700路公交车正在赶来");
            SmallTools.sleepMills(100);
            return "700";
        }).applyToEitherAsync(CompletableFuture.supplyAsync(() -> {
            SmallTools.printTimeAndThread("800路公交车正在赶来");
            SmallTools.sleepMills(100);
            SmallTools.printTimeAndThread("800路公交车正在赶来。。。。。。。。。");
            return "800";
        }), res -> {
            if (res.equals("700")) {
                throw new RuntimeException("700路公交撞树了");
            }
            return res;
        }).exceptionally(e -> {
            SmallTools.printTimeAndThread(e.getMessage());
            SmallTools.printTimeAndThread("小白叫了出租车");
            return "出租车";
        });

        SmallTools.printTimeAndThread(String.format("小白做%s回家", completableFuture.join()));
    }

8.扩展

  1. runAsync(Runnable runnable) 不需要返回值的时候可以是使用该方法
    supplyAsync(Supplier supplier) 有返回值

  2. thenApply 需要接收前一个返回值,也需要返回结果 BiFunction()
    thenRun 不需要接收前一个任务返回值,也不需要返 回结果
    thenAccept 接受前一个任务返回值,不需要返回一个结果 consumer()

  3. thenCombine 需要接收前两个返回值,也需要返回结果 BiFunction()
    thenAcceptBoth 接受前两个任务返回值,不需要返回一个结果 consumer()
    runAfterBoth 不需要接收前两个任务返回值,也不需要返回结果

4.applyToEither 那个任务先执行完成就会使用那个任务的结果
acceptEither 会得到最快任务执行完的返回值,没有返回结果
runAfterEither 即没有使用返回值,也不需要返回结果

5.exceptionally 捕获异常,并且返回结果
6.handle(BiFunction<Throwable,Object>) 有两个参数,如果前面的任务跑出异常就会收到异常结果,如果是正常的就会收到正常结果。但是无论正常还是异常都会返回一个结果,让后面的程序还是会正常执行
7.whenComplete(BiFunction<Throwable,Object>) 跟handle一样,但是没有返回值

8.不带async的方法就是先当于把后一个任务代码交给 上个执行任务线程执行了
9. 带async的方法,会有两个不同的线程进行执行,但是由于使用线程池,会发生线程复用,所以打印出来的线程有的时候是同一个线程
9.allOf,等待所有的任务执行完成

 public static void test2(){
        SmallTools.printTimeAndThread("小白和小伙伴们进入餐厅点菜");
        long start = System.currentTimeMillis();
        CompletableFuture[] completableFutures = (CompletableFuture[]) IntStream.rangeClosed(1, 10)
                .mapToObj(i -> new Dish("菜" + i, 1))
                .map(dish -> CompletableFuture.runAsync(dish::make))
                .toArray(size -> new CompletableFuture[size]);
        CompletableFuture.allOf(completableFutures).join();

        SmallTools.printTimeAndThread("一共用了" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start));
        //
        SmallTools.printTimeAndThread(String.valueOf(Runtime.getRuntime().availableProcessors()));
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值