CompletableFuture如何使用

CompletableFuture创建异步任务的三种方法:
completedFuture-用于构建一个现成的CompletableFuture对象,
runAsync-没有返回值,
supplyAsync-支持返回值
获取CompletableFuture结果的方法有两个:join(),get().二者的区别在于join方法抛出的是RuntimeException,不需要显式进行处理,而使用get就需要显式捕获异常。
get可以设定超时时间,getNow可以设定默认值,当未获取到future值或者出现异常时,则返回设定的默认值
注意:get,join方法是获取线程的结果,不是让线程执行,所以即使不加get,join方法线程也会执行
复制代码
      //使用自定义线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        //runAsync的使用,如果不指定自定义线程池就用默认的ForkJoinPool.commonPool线程池
        CompletableFuture<String> future1 = CompletableFuture.completedFuture("hello world");
        CompletableFuture<Void> runFuture = CompletableFuture.runAsync(() -> System.out.println("runAsync执行语句"), executor);
        //supplyAsync的使用
        CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("supplyAsync执行语句");
            return "supplyAsync返回语句";
        }, executor);
        //runAsync的future没有返回值,输出null
        System.out.println(runFuture.join());
        //supplyAsync的future,有返回值
        System.out.println(supplyFuture.join());
        try {
            future1.get(1000, TimeUnit.MILLISECONDS);//需要处理异常,可以设置超时时间
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            throw new RuntimeException(e);
        }
   /*     future1.join();//无需处理异常
        future1.getNow("默认值");//可以设置默认值*/

        executor.shutdown(); // 线程池需要关闭
复制代码
CompletableFuture的简单异步回调方法
1:不关心上一个任务的执行返回结果,无传参,无返回值-thenRun/thenRunAsync
thenRun和thenRunAsync的区别:如果执行第一个任务的时候,传入了一个自定义线程池,调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池,调用thenRunAsync执行第二个任务时,则第一个任务使用的是自己传入的线程池,第二个任务使用的是ForkJoin线程池.
后面的thenAccept和thenAcceptAsync,thenApply和thenApplyAsync等,它们之间的区别也是这个
复制代码
 CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("先执行第一个CompletableFuture方法任务");
                    return "任务一执行完成";
                }
        );

        CompletableFuture thenRunFuture = orgFuture.thenRun(() -> {
            System.out.println("接着执行第二个任务");
        });
        System.out.println(thenRunFuture.get());
复制代码
CompletableFuture的简单异步回调方法
2:thenAccept/thenAcceptAsync
CompletableFuture的thenAccept方法表示,第一个任务执行完成后,执行第二个任务,会将任务一的执行结果作为入参,传递到任务二方法中,但是任务二是没有返回值的。
复制代码
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("CompletableFuture任务一");
                    return "任务一返回值";
                }
        );

        CompletableFuture thenAcceptFuture = orgFuture.thenAccept((a) -> {
            if ("任务一返回值".equals(a)) {
                System.out.println("一致");
            } else {
                System.out.println("不一致");
            }
        });
        System.out.println(thenAcceptFuture.get());
复制代码
CompletableFuture的简单异步回调方法:
3.thenApply/thenApplyAsync
 CompletableFuture的thenApply方法表示,第一个任务执行完成后,执行第二个任务,会将任务一的执行结果作为入参,传递到任务二方法中,任务二有返回值。
复制代码
CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("CompletableFuture任务一");
                    return "任务一返回值";
                }
        );

        CompletableFuture<String> thenAcceptFuture = orgFuture.thenApply((a) -> {
            if ("任务一返回值".equals(a)) {
                System.out.println("一致");
            } else {
                System.out.println("不一致");
            }
            return "任务二返回值";
        });
        System.out.println(thenAcceptFuture.get());
复制代码
CompletableFuture的简单异步回调方法:
4.exceptionally
CompletableFuture的exceptionally方法表示,某个任务执行异常时,执行的回调方法;并且有抛出异常作为参数,传递到回调方法。
复制代码
  CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("CompletableFuture任务一");
                    return "任务一返回值";
                }
        );

        CompletableFuture<String> thenAcceptFuture = orgFuture.thenApply((a) -> {
            if ("任务一返回值".equals(a)) {
                System.out.println("一致");
            } else {
                System.out.println("不一致");
            }
            throw new RuntimeException();
        });
        CompletableFuture<String> exceptionFuture = thenAcceptFuture.exceptionally((e) -> {
            e.printStackTrace();
            return "你的程序异常啦";
        });
        System.out.println(exceptionFuture.get());
复制代码
CompletableFuture的简单异步回调方法:
5.whenComplete
CompletableFuture的whenComplete方法表示,某个任务执行完成后,执行的回调方法,无返回值;并且whenComplete方法返回的CompletableFuture的result是上个任务的结果。
复制代码
 CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("当前线程名称:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "任务一返回结果";
                }
        );
        CompletableFuture<String> rstFuture = orgFuture.whenComplete((a, throwable) -> {
            System.out.println("当前线程名称:" + Thread.currentThread().getName());
            System.out.println("上个任务执行完啦,还把" + a + "传过来");
            if ("任务一返回结果".equals(a)) {
                System.out.println("一致");
            }
        });
        System.out.println(rstFuture.get());
复制代码
CompletableFuture的简单异步回调方法:
6.handle
CompletableFuture的handle方法表示,某个任务执行完成后,执行回调方法,并且是有返回值的;并且handle方法返回的CompletableFuture的result是回调方法执行的结果。
复制代码
 CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                () -> {
                    System.out.println("当前线程名称:" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "任务一返回结果";
                }
        );

        CompletableFuture<String> rstFuture = orgFuture.handle((a, throwable) -> {
            System.out.println("当前线程名称:" + Thread.currentThread().getName());
            System.out.println("上个任务执行完啦,还把" + a + "传过来");
            if ("任务一返回结果".equals(a)) {
                System.out.println("一致");
            }
            return "任务二返回值";
        });

        System.out.println(rstFuture.get());
复制代码
thenCombine / thenAcceptBoth / runAfterBoth都表示:将两个CompletableFuture组合起来,只有这两个都正常执行完了,才会执行某个任务。
区别在于:
thenCombine:会将两个任务的执行结果作为方法入参,传递到指定方法中,且有返回值
thenAcceptBoth: 会将两个任务的执行结果作为方法入参,传递到指定方法中,且无返回值
runAfterBoth 不会把执行结果当做方法入参,且没有返回值
这三个都可以用后面的AllOf代替
复制代码
CompletableFuture<String> first = CompletableFuture.completedFuture("第一个异步任务");
        ExecutorService executor = Executors.newFixedThreadPool(10);
        CompletableFuture<String> future = CompletableFuture
                //第二个异步任务
                .supplyAsync(() -> "第二个异步任务", executor)
                // (w, s) -> System.out.println(s) 是第三个任务
                .thenCombineAsync(first, (s, w) -> {
                    System.out.println(w);
                    System.out.println(s);
                    return "两个异步任务的组合";
                }, executor);
        System.out.println(future.join());
        executor.shutdown();
复制代码
applyToEither / acceptEither / runAfterEither 都表示:将两个CompletableFuture组合起来,只要其中一个执行完了,就会执行某个任务。
区别在于:
applyToEither:会将已经执行完成的任务,作为方法入参,传递到指定方法中,且有返回值
acceptEither: 会将已经执行完成的任务,作为方法入参,传递到指定方法中,且无返回值
runAfterEither: 不会把执行结果当做方法入参,且没有返回值。
这三个都可以用后面的anyof代替
复制代码
 //第一个异步任务,休眠2秒,保证它执行晚点
        CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
            try{

                Thread.sleep(2000L);
                System.out.println("执行完第一个异步任务");}
            catch (Exception e){
                return "第一个任务异常";
            }
            return "第一个异步任务";
        });
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> future = CompletableFuture
                //第二个异步任务
                .supplyAsync(() -> {
                            System.out.println("执行完第二个任务");
                            return "第二个任务";}
                        , executor)
                //第三个任务
                .acceptEitherAsync(first, System.out::println, executor);

        executor.shutdown();
复制代码
AllOf:所有任务都执行完成后,才执行 allOf返回的CompletableFuture。如果任意一个任务异常,allOf的CompletableFuture,执行get方法,会抛出异常
需要注意的是,由于allof是获取所有CompletableFuture对象的结果,因此无法确认返回的类型,所以allof返回的是CompletableFuture<void>对象
复制代码
  CompletableFuture<Void> a = CompletableFuture.runAsync(()->{
            System.out.println("我执行完了");
        });
        CompletableFuture<Void> b = CompletableFuture.runAsync(() -> {
            System.out.println("我也执行完了");
        });
        CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(a, b).whenComplete((m,k)->{
            System.out.println("finish");
        });
复制代码
任意一个任务执行完,就执行anyOf返回的CompletableFuture。如果执行的任务异常,anyOf的CompletableFuture,执行get方法,会抛出异常
复制代码
CompletableFuture<Void> a = CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我执行完了");
        });
        CompletableFuture<Void> b = CompletableFuture.runAsync(() -> {
            System.out.println("我也执行完了");
        });
        CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(a, b).whenComplete((m,k)->{
            System.out.println("finish");
        });
复制代码
CompletableFuture使用需要注意的几点:
1- Future需要获取返回值,才能获取异常信息
2-自定义线程池时,注意饱和策略,如果线程池拒绝策略是DiscardPolicy或者DiscardOldestPolicy,
当线程池饱和时,会直接丢弃任务,不会抛弃异常。因此建议,CompletableFuture线程池策略最好使用AbortPolicy(线程池默认的拒绝策略,它会丢弃任务并抛出 `RejectedExecutionException` 异常。这有助于及时反馈程序运行状态),然后耗时的异步线程,做好线程池隔离
  ExecutorService executorService = new ThreadPoolExecutor(5, 10, 5L,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            int a = 0;
            int b = 666;
            int c = b / a;
            return true;
        },executorService).thenAccept(System.out::println);
总结:
thenRun,thenAccept,thenApply和他们的异步方法都是代表下一步要做的任务,只是有没有参数和返回值的区别
CompletableFuture常用的几个方法:
两个创建异步任务方法: runAsync-没有返回值,supplyAsync-支持返回值
三个开启下个任务的thenXXX方法
两个获取结果方法: get,join ,
allOf,anyOf方法, 其他用的不多
 
posted @   杨吃羊  阅读(286)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示