首页 > 其他分享 >CompletableFuture如何使用

CompletableFuture如何使用

时间:2024-01-19 16:11:08浏览次数:23  
标签:System 如何 任务 CompletableFuture 使用 println 返回值 out

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方法, 其他用的不多  

标签:System,如何,任务,CompletableFuture,使用,println,返回值,out
From: https://www.cnblogs.com/1--2/p/17974921

相关文章

  • 封装的子组件,才fromitem中,子组件的变化,如何被form监听到。
    子组件,应该有个onChange事件。问题:在嵌入自定义组件时,需要将子组件的onChange方法暴露出去。原因:1.form会监听的onChange方法和value变量(form是的一个属性)2.其它基于封装的组件如:,自定义的方法名必须叫onChange,变量名必须叫value,否则自定义组件的状态变化不能被form表单的onCha......
  • 使用 Docker 安装 Elasticsearch (本地环境 M1 Mac)
    Elasticsearch+kibana下载安装dockerpullelasticsearch:7.16.2dockerrun--namees-d-eES_JAVA_OPTS=“-Xms512m-Xmx512m”-e“discovery.type=single-node”-p9200:9200-p9300:9300elasticsearch:7.16.2dockerpullkibana:7.16.2dockerrun--namekibana-eELAST......
  • 初次使用git
    1.在gitee新建仓库2.在本地文件夹下初始化仓库:gitinit3.提交所有文件到缓冲区:gitadd.4.提交缓冲区文件到本地仓库:gitcommit-m"initialcode"5.关联本地仓库与远程仓库:gitremoteaddorigingitee仓库地址第6到10步为错误命令。6.gitpulloriginmaster提示有偏离......
  • 1-STM32F103+EC800K(移远4G Cat1)远程升级篇(阿里云物联网平台)-STM32F103使用EC800K
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ZLIOTB/EC800K/aliyunota.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p>  ......
  • redis漏洞修复-使用redis普通用户启动redis服务程序(禁止root用户权限)
    2.Redis服务以root权限运行应用:Redis危险程度:高危风险描述:Redis服务以root权限运行,攻击者可通过Redis对服务器文件进行任意操作或者执行命令。通过查询命令获取敏感信息,通过写入公钥信息获取ssh登录权限等。如果Redis为root权限,攻击者则无需提权直接对服务器进行操作。验证信息......
  • (8)Powershell中变量的定义和使用
    (8)Powershell中变量的定义和使用这一节主要介绍Powershell中变量的定义和使用,以及使用变量时应该注意的事项。和所有编程语言中的变量一样,Powershell中的变量也是存于存储值的内存单元,需要注意的是,Powershell中的变量是以美元符号($)开头的单字节(一般是英文字符,虽然ISE中支持......
  • 公司数百名项目经理如何交流,微信群不管用,可以尝试这个方法
    我们公司有两百多位项目经理,分散在全国各地。 虽然我们有个”项目经理群“,但分享互动效果很差。最热闹的场景还是金主们发红包的时候。 这可能与群的性质有关,工作和灌水之间的界限较模糊,大家发消息时,总有点儿顾及。 项目经理之间的沟通和经验分享是主动学习的一种较好方......
  • 如何缓解现代企业亟需应对的数据安全难题?
    在......
  • 优化风潮下的Android开发者:如何保持竞争力?
    作为一名曾在知名大厂和腾讯工作的程序员,我想分享一下对于职场焦虑的看法。很多程序员都会在职场中遇到焦虑,这不仅来自工作环境,也与个人心态有关。焦虑的原因主要有两个方面:精神压力和竞争压力。我的一个朋友就是这样的,普通本科的学历,去年6月份进的大厂,刚刚开始的时候因为不熟悉工......
  • windows中如何在右键新建菜单中添加新的可创建项目(转)
    当在Windows桌面单击鼠标右键,选择“新建”来建立快捷方式或文件夹时,除了快捷方式与文件夹这2个选项之外,还有一个很长的文件菜单,包含了电脑中安装的一些应用软件,你可以很容易地建立文件列表中所包含类型的新文件。在这里向您介绍如何通过修改注册表来定制鼠标右键快捷菜单中的“新......