Java CompletableFuture常用方法

本文介绍了Java中的CompletableFuture类,用于处理异步任务。通过supplyAsync和runAsync创建异步任务,利用不同的方法如get、join、complete等管理任务的执行和结果。文章还探讨了异常处理、任务回调(whenComplete、exceptionally)、顺序执行(thenRun、thenAccept、thenApply)以及多任务组合处理(thenCombine、applyToEither)等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步任务

supplyAsync是创建带有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool

.commonPool())的方法,一个是带有自定义线程池的重载方法

 CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{
     System.out.println(Thread.currentThread().getName()+"在执行");
     int i = 1/0;
     return 1024;
 });


runAsync

创建不包含返回值的异步任务,其他与supplyAsync类似

 CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{
     System.out.println(Thread.currentThread().getName()+"正在执行");
 });

获取任务回调

 ​
 // 如果完成则返回结果,否则就抛出具体的异常
 public T get() throws InterruptedException, ExecutionException 
  
 // 最大时间等待返回结果,否则就抛出具体异常
 public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
  
 // 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因
 public T join()
  
 // 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
 public T getNow(T valueIfAbsent)
  
 // 如果任务没有完成,返回的值设置为给定值
 public boolean complete(T value)
  
 // 如果任务没有完成,就抛出给定异常
 public boolean completeExceptionally(Throwable ex)

最后执行的代码块

whenComplete

异步任务的回调完成后执行,下面是函数式接口,第一个参数为回调结果,第二个参数为Exception

 new BiConsumer<Integer, Throwable>(){}


 //设置回调函数
 completableFuture2.whenComplete(new BiConsumer<Integer, Throwable>() {
 ​
     @Override
     public void accept(Integer unused, Throwable throwable) {
         System.out.println(unused);
         System.out.println(throwable);
     }
 }).get();

exceptionally

当异步任务中有异常抛出时会执行,函数式接口中只有一个参数为Exception类型

 CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
     Integer result = new Random().nextInt(5);
     System.out.println(Thread.currentThread().getName() + "休息一秒钟");
     try {
         TimeUnit.SECONDS.sleep(1);
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
     if (result < 3) {
         int a = 10/0;
     }
     return result;   //这里使用我自己定义的线程池
 },executorService).whenComplete((r,e)->{  //r为返回的结果,e则为返回的Exception对象
     if (e==null) {
         System.out.println("返回的结果为"+r);
     }
 }).exceptionally(e->{  //最后抛出了异常就会执行的方法
     e.printStackTrace();
     System.out.println("抛出了异常");
     return null;
 });

后缀为Async的API

thenRunthenRunAsync为例:

①:没有传入自定义的线程池,两种api都会默认使用ForkJoinPool来作为线程池

②:如果在执行第一个任务时 传入了一个自定义线程池,

调用thenRun会和上一个任务共用同一个线程池,

调用thenRunAsync,上一个线程池使用自定义的线程池,下一个任务使用ForkJoinPool线程池

③:执行过快时,系统可能进行优化,直接使用main线程处理

其他api同理

 ExecutorService executorService = Executors.newFixedThreadPool(5);
 ​
 CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
     System.out.println("hello world"+Thread.currentThread());
 },executorService);
 cf.thenRunAsync(()->{
             try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
             System.out.println("这是第一个方法"+Thread.currentThread().getName());
             }
         ).thenRun(()->{
             try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
             System.out.println("这是第二个方法"+Thread.currentThread().getName());
         }).thenRun(()->{
             try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
             System.out.println("这是第三个方法"+Thread.currentThread().getName());
         });
 ​
 System.out.println(cf.join());
 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
 executorService.shutdown();

顺序执行

thenRun

Runable runnable 接口

任务A执行完执行B,并且B不需要A的结果

thenAccept

Runable runnable 接口

任务A执行完执行B,B需要A的结果,但是B无返回值

thenApply

Runable runnable 接口

任务A执行完执行B,B需要A的结果,同时B有返回值

 ExecutorService executorService = Executors.newFixedThreadPool(3);
 //CompletableFuture实现多个线程之间的串行化执行
 CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
     System.out.println("111");
     return 1;
 },executorService).thenApply((a)->{
     System.out.println("222");
     int i = 1/0;
     return a+2;
 }).thenApply((a)->{
     System.out.println("333");
     return a+3;
 }).whenComplete((v,e)->{
     if (e==null) {  //没有发生错误
         System.out.println("最终结果是:"+v);
     }
 }).exceptionally(e->{  //发生了异常执行
     e.printStackTrace();
     return null;
 });
 ​
 System.out.println("main线程忙其他工作去了");
 ​
 executorService.shutdown();

handle

handle所需要接口的参数与whenComplete相同,但是handle接口是需要返回值的。同时如果执行过程中出现了异常是不会抛出的。

 CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
     System.out.println("111");
     return 1;
 },executorService).handle((a,b)->{
     System.out.println("222");
     int i = 1/0;
     return a+2;
 })

多任务组合处理

thenCombine

参数需要一个要组合的CompletableFuture对象,和一个(a,b) -> return a+b; 类似的接口,来完成对两个任务结果的合并 

 CompletableFuture<Integer> theLastResult = CompletableFuture.supplyAsync(()->{
     System.out.println("正在进行第一次计算");
     return 10;
 }).thenCombine(CompletableFuture.supplyAsync(()->{
     System.out.println("正在进行第二次计算");
     return 20;
 }),(a,b)->{
     return a+b;
 }).thenCombine(CompletableFuture.supplyAsync(()->{
     System.out.println("正在进行第三次计算");
     return 30;
 }),(a,b)->a+b);
 ​
 ​
 //开始获取最后结果
 System.out.println("main: 最后结果为" + theLastResult.join());

applyToEither

获取到两个异步任务中先完成任务的回调,参数为 CompeltableFuture和一个Function接口实现类

 CompletableFuture<String> playerA = CompletableFuture.supplyAsync(()->{
     System.out.println("A come in");
     try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
     return "A";
 });
 ​
 CompletableFuture<String> playerB = CompletableFuture.supplyAsync(()->{
     System.out.println("B come in");
     try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
     return "B";
 });
 ​
 //再开一个异步任务比较两个线程之间执行速度的比较
 ​
 CompletableFuture<String> winner = playerA.applyToEither(playerB, r -> {
     return r;
 });
 ​
 //获取最终结果
 System.out.println("最终赢家为:"+winner.join());

刚刚学完CompletableFuture,以此总结一番,如果存在错误,欢迎大家提出来

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值