CompletableFuture整理及拓展

思维导图

CompletableFuture使用及api介绍

一.创建CompletableFuture对象

//异步执行一个有返回值的任务
CompletableFuture demoFuture1 = CompletableFuture.supplyAsync(()->{ return "ss";});
//异步执行一个无返回值的任务
CompletableFuture demoFuture2 = CompletableFuture.runAsync(()->{System.out.println("ss");});
//创建一个已经完成的CompletableFuture对象
CompletableFuture demoFuture3 = CompletableFuture.completedFuture("ss");
// 创建一个未完成的CompletableFuture对象
CompletableFuture  demoFuture4 = new CompletableFuture();

二.组合CompletableFuture对象

//在CompletableFuture对象上执行一个函数,并返回一个新的带返回值的CompletableFuture对象
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");
CompletableFuture demoFuture2 = demoFuture1.thenApply((String s)->{    return s+"t";});

//在CompletableFuture对象上执行一个消费者,并返回一个新的CompletableFuture对象
CompletableFuture demoFuture3 = demoFuture1.thenAccept((String s)->{   System.out.println(s);});

//在CompletableFuture对象上执行一个Runnable,并返回一个新的CompletableFuture对象
CompletableFuture demoFuture4 = demoFuture1.thenRun(()->{    System.out.println("ss");});

//在CompletableFuture对象上执行一个函数,返回一个新的CompletableFuture对象 和thenApply很像,但是需要自己手动返回CompletableFuture对象
CompletableFuture<String> demoFuture5 = demoFuture1.thenCompose((String s)->{       
       System.out.println(s); 
       return new CompletableFuture();
});
//将两个CompletableFuture对象的结果组合起来,并执行一个函数,返回一个新的
CompletableFuture对象demoFuture1.thenCombine(demoFuture5,(t,s)->{    return s+t;});

//allOf(CompletableFuture... cfs):等待所有的CompletableFuture对象执行完成
CompletableFuture  allofCompletableFuture = CompletableFuture.allOf(demoFuture1,demoFuture2);

//anyOf(CompletableFuture... cfs):等待任意一个CompletableFuture对象执行完成
CompletableFuture  anyofCompletableFuture = CompletableFuture.anyOf(demoFuture1,demoFuture2);

//acceptEither(CompletionStage other, Consumer action):两个CompletableFuture对象任意一个完成后执行指定的消费者
CompletableFuture acceptEitherFuture = demoFuture1.acceptEither(demoFuture2,(s)->{    System.out.println(s);});

//applyToEither(CompletionStage other, Function fn):两个CompletableFuture对象任意一个完成后执行指定的函数,并返回一个新的CompletableFuture对象
CompletableFuture applyToEitherFuture =  demoFuture1.applyToEither(demoFuture2,(s)->{    return s;});

//runAfterBoth(CompletionStage other, Runnable action):两个CompletableFuture对象都完成后执行指定的Runnable
CompletableFuture runAfterBothFuture =  demoFuture1.runAfterBoth(demoFuture2,()->{    System.out.println("ss");});

//runAfterEither(CompletionStage other, Runnable action):两个CompletableFuture对象任意一个完成后执行指定的Runnable
CompletableFuture runAfterEitherFuture =  demoFuture1.runAfterEither(demoFuture2,()->{    System.out.println("ss");});

//thenAcceptBoth(CompletionStage other, BiConsumer action):将两个CompletableFuture对象的结果组合起来,并执行一个消费者
CompletableFuture thenAcceptBothFuture = demoFuture1.thenAcceptBoth(demoFuture2,(s,t)->{    System.out.println(s);    System.out.println(t);});

三.处理CompletableFuture对象的结果

//get():获取CompletableFuture对象的结果,如果任务还未完成,则会阻塞等待
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");
try {    
  demoFuture1.get();
} catch (InterruptedException e) 
{    
  e.printStackTrace();
} catch (ExecutionException e) {    
  e.printStackTrace();
}
//get(long timeout, TimeUnit unit):获取CompletableFuture对象的结果,如果任务还未完成,则会阻塞等待一段时间
try {    
   demoFuture1.get(1000, TimeUnit.MILLISECONDS);
   } catch (InterruptedException e) {    
     e.printStackTrace();
   } catch (ExecutionException e) {   
    e.printStackTrace();
   } catch (TimeoutException e) {    
    e.printStackTrace();
   }
//join():获取CompletableFuture对象的结果,如果任务还未完成,则会一直阻塞,和get的区别在于不抛出异常,get方法需要手动捕获
demoFuture1.join();
//cancel(boolean mayInterruptIfRunning):尝试取消CompletableFuture对象的执行
demoFuture1.cancel(true);
//isCancelled():判断CompletableFuture对象是否被取消
demoFuture1.isCancelled();
//isCompletedExceptionally():判断CompletableFuture对象是否执行异常
demoFuture1.isCompletedExceptionally();
//isDone():判断CompletableFuture对象是否执行完成
demoFuture1.isDone();

四.结果异常处理

//exceptionally(Function fn):处理CompletableFuture对象执行过程中的异常
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");

demoFuture1.exceptionally((Throwable e)->{    
 System.out.println(e.getMessage());    
 return "s";
});

//handle(BiFunction fn):处理CompletableFuture对象执行过程中的异常,同时处理正常结果
demoFuture1.handle((t,e)->{    
 System.out.println(t.toUpperCase());   
 System.out.println(e.getMessage());    
 return "s";
});

五.指定业务线程池

private static final Executor executor = TtlExecutors.getTtlExecutor(new ThreadPoolExecutor(1,1,3000, TimeUnit.MILLISECONDS,new ArrayBlockingQueue(100)));
//使用指定的线程池执行异步任务,不指定的话默认走ForkJoinPool线程池
//默认ForkJoinPool线程池,ForkJoinPool里面的线程都是daemon线程,非daemon线程都结束后,虚拟机也就退出了。
//如果需要执行较长时间或执行内容比较重要不希望被中断而导致数据不一致的话,那就自己传一个Executor吧

CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss",executor);
CompletableFuture demoFuture2 = CompletableFuture.runAsync(()->{    System.out.println("s");},executor);

源码介绍

一.CompletionStage

CompletionStage可以用于构建复杂的异步计算流水线,通过串行、并行、组合等方式来处理异步计算的结果。

CompletableFuture实现了接口CompletionStage来处理组合和编排CompletableFuture对象之类操作。

如下图,包括等等这些操作。

二.FunctionalInterface

FunctionalInterface是Java8引入的一个新特性,用于表示一个接口是函数式接口。函数式接口是只包含一个抽象方法的接口,可以被Lambda表达式所实现。

FunctionalInterface的特点: - 只能包含一个抽象方法,可以有多个默认方法和静态方法。

CompletionStage 组合CompletableFuture对象时大量使用FunctionalInterface

例如下面的函数式接口 就是CompletionStage的thenAcceptBoth的方法入参。

三.ForkJoinPool

CompletableFuture的任务提交的时候默认使用ForkJoinPool线程池来处理。

它是一个特殊的线程池,可以充分利用多核处理器的性能,提高并发性能,内部使用工作窃取算法来提高任务的执行效率。

ForkJoinPool可以将一个大任务拆分成多个小任务,并行执行这些小任务,最后合并结果。

四.Completion

如下图,CompletableFuture成员变量,Completion对象stack,这是一个CAS实现的无锁并发栈,每个链式调用的任务会被压入这个栈

如下图,本身Completion的成员变量Completion,next指向,并继承ForkJoinTask,默认的线程池是ForkJoinPool

通过这两个特性来进行链式调用,可以参考这篇文章 深入理解JDK8新特性CompletableFuture-阿里云开发者社区

CompletableFuture优缺点

优点

1. 异步编程:CompletableFuture提供了一种简单且强大的方式来进行异步编程,可以避免阻塞线程,提高系统的并发性能。

2. 链式操作:CompletableFuture支持链式调用,可以通过一系列的操作来组合多个CompletableFuture,实现复杂的异步任务。

3. 异常处理:CompletableFuture提供了异常处理的机制,可以通过exceptionally()、handle()等方法来处理异常,保证程序的健壮性。

4. 高度可定制性:CompletableFuture提供了丰富的方法来定制异步任务的执行方式,可以设置超时时间、执行顺序、并发级别等。

缺点

1. 学习成本高:CompletableFuture的使用相对复杂,需要掌握一些异步编程的概念和技巧,对于初学者来说学习成本较高。

2. 可读性差:由于CompletableFuture支持链式调用,代码可能会变得冗长和难以理解,特别是当有多个异步任务需要组合时。

3. 线程资源占用:CompletableFuture在执行异步任务时会占用一定的线程资源,如果不合理地使用CompletableFuture,可能会导致线程资源的浪费。

CompletableFuture的拓展

1.如何支持将多个超过两个以上的CompletableFuture对象进行合并

具体参考逻辑如下

<think>嗯,用户之前问过如何控制线程池中线程的执行顺序,我之前回答了包括使用CompletableFuture的方法。现在用户接着问CompletableFuture的作用和使用方法,说明他们对这个主题感兴趣,可能在实际开发中遇到了异步任务处理的问题。 首先,我需要明确用户的真实需求。他们可能正在处理需要顺序执行或组合多个异步任务的场景,比如链式调用、并行执行多个任务后合并结果,或者处理异常。CompletableFutureJava中正是用来简化这些复杂异步操作的,所以用户需要的是如何有效利用它来优化代码结构,提升效率。 接下来,用户可能对CompletableFuture的基础概念不太熟悉,需要先解释它的作用,比如异步编程、任务编排、异常处理等。然后,需要给出具体的使用方法,最好有代码示例,让用户能够直观理解。同时,用户可能希望了解不同方法的适用场景,比如thenApply和thenCompose的区别,如何处理多个任务的组合等。 还要注意用户可能存在的误区。例如,他们可能认为使用CompletableFuture会自动提升性能,但实际上需要正确配置线程池。此外,异常处理容易被忽视,需要强调whenComplete或exceptionally方法的重要性。 用户可能没有提到但需要涵盖的内容包括:CompletableFuture与Future的区别,它如何支持非阻塞操作,以及如何结合Lambda表达式使代码更简洁。此外,实际应用中的常见模式,如并行执行多个任务后等待所有完成,或者任一完成即处理结果,都是用户可能会用到的。 最后,需要总结使用建议,帮助用户避免常见错误,比如线程池的选择和资源管理,以及强调CompletableFuture在简化异步编程中的优势。同时,提醒他们在复杂场景下可能需要结合其他技术,如响应式编程库。</think>好的!`CompletableFuture` 是 Java 8 引入的异步编程工具,**核心作用是简化多任务编排**,支持链式调用、组合异步任务和异常处理。以下是详细解析: --- ### 一、核心作用 1. **异步执行** 将任务提交到线程池执行,不阻塞主线程 ```java CompletableFuture.runAsync(() -> System.out.println("异步任务")); ``` 2. **任务链式编排** 支持 `thenApply`/`thenAccept`/`thenRun` 串联任务 ```java CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") // 转换结果 .thenAccept(System.out::println); // 消费结果 ``` 3. **组合多个任务** - `allOf`: 等待所有任务完成 - `anyOf`: 任一任务完成即触发 ```java CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2); ``` 4. **异常处理** 通过 `exceptionally` 或 `handle` 捕获异常 ```java CompletableFuture.supplyAsync(() -> 1/0) .exceptionally(ex -> { System.out.println("Error: " + ex); return 0; // 默认值 }); ``` --- ### 二、基础使用示例 #### 场景1:异步执行 + 链式处理 ```java CompletableFuture.supplyAsync(() -> { // 模拟耗时操作 try { Thread.sleep(1000); } catch (Exception e) {} return "Data"; }).thenApply(data -> data.toUpperCase()) // 转换结果 .thenAccept(result -> System.out.println(result)); // 输出 "DATA" ``` #### 场景2:合并两个异步结果 ```java CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello"); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World"); future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2) .thenAccept(System.out::println); // 输出 "Hello World" ``` #### 场景3:异常回退 ```java CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { if (Math.random() > 0.5) throw new RuntimeException("模拟异常"); return 42; }).exceptionally(ex -> { // 异常时返回默认值 System.out.println("Fallback due to: " + ex.getMessage()); return 0; }); ``` --- ### 三、关键方法速查 | 方法 | 作用 | 示例 | |---------------------|--------------------------------------|---------------------------------------| | `supplyAsync()` | 提交有返回值的异步任务 | `supplyAsync(() -> "value")` | | `thenApply()` | 对结果进行转换 | `future.thenApply(s -> s.length())` | | `thenCompose()` | 连接另一个`CompletableFuture` | `future.thenCompose(f -> newFuture)` | | `thenAccept()` | 消费结果(无返回值) | `future.thenAccept(System.out::println)` | | `handle()` | 处理结果或异常 | `future.handle((res, ex) -> ex != null ? 0 : res)` | | `allOf()/anyOf()` | 组合多个任务 | `CompletableFuture.allOf(f1, f2)` | --- ### 四、最佳实践建议 1. **明确线程池** 默认使用 `ForkJoinPool.commonPool()`,建议自定义线程池避免资源竞争: ```java ExecutorService customPool = Executors.newFixedThreadPool(4); CompletableFuture.supplyAsync(() -> task(), customPool); ``` 2. **避免阻塞** 尽量使用回调(如 `thenAccept`)而非 `get()`,防止线程卡死 3. **异常优先处理** 通过 `exceptionally` 或 `handle` 避免未捕获异常导致任务静默失败 4. **复杂任务拆分** 对多步骤异步操作,用链式调用替代嵌套回调,提升可读性 --- ### 五、适用场景 - 需要**多个异步任务顺序执行**(如:先查询A再根据A结果查询B) - 需要**并行执行任务后合并结果**(如:同时调用两个API,合并数据) - 需要**灵活处理超时或异常**的异步操作 --- 通过 `CompletableFuture`,开发者可以用**声明式代码**替代传统回调地狱,显著提升异步代码的可维护性!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值