CompletableFuture实现异步编排全面分析和总结

article/2025/10/28 7:22:56

一、🌈CompletableFuture简介

CompletableFuture结合了Future的优点,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。

CompletableFuture被设计在Java中进行异步编程。异步编程意味着在主线程之外创建一个独立的线程,与主线程分隔开,并在上面运行一个非阻塞的任务,然后通知主线程进展,成功或者失败。

CompletableFuture是由Java8引入的,在Java8之前我们一般通过Future实现异步。

  • Future用于表示异步计算的结果,只能通过阻塞或者轮询的方式获取结果,而且不支持设置回调方法,Java8之前若要设置回调一般会使用guavaListenableFuture
  • CompletableFutureFuture进行了扩展,可以通过设置回调的方式处理计算结果,同时也支持组合操作,支持进一步的编排,同时一定程度解决了回调地狱的问题。

✔本文的名词缩写:

  • CF:代表CompletableFuture
  • CS:代表CompletionStage

二、CompletableFuture 核心接口API介绍

2.1 Future

使用Future局限性

从本质上说,Future表示一个异步计算的结果。它提供了isDone()来检测计算是否已经完成,并且在计算结束后,可以通过get()方法来获取计算结果。在异步计算中,Future确实是个非常优秀的接口。但是,它的本身也确实存在着许多限制:

  • 并发执行多任务Future只提供了get()方法来获取结果,并且是阻塞的。所以,除了等待你别无他法;
  • 无法对多个任务进行链式调用:如果你希望在计算任务完成后执行特定动作,比如发邮件,但Future却没有提供这样的能力;
  • 无法组合多个任务:如果你运行了10个任务,并期望在它们全部执行结束后执行特定动作,那么在Future中这是无能为力的;
  • 没有异常处理Future接口中没有关于异常处理的方法;
方法说明描述
booleancancel (boolean mayInterruptIfRunning)尝试取消执行此任务。
Vget()如果需要等待计算完成,然后检索其结果。
Vget(long timeout, TimeUnit unit)如果需要,最多等待计算完成的给定时间,然后检索其结果(如果可用)。
booleanisCancelled()如果此任务在正常完成之前取消,则返回 true 。
booleanisDone()如果此任务完成,则返回 true 。

2.2 CompletableFuture

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {}
复制代码

JDK1.8 才新加入的一个实现类CompletableFuture,而CompletableFuture实现了两个接口(如上面代码所示):Future<T>CompletionStage<T>,意味着可以像以前一样通过阻塞或者轮询的方式获得结果。

Future表示异步计算的结果,CompletionStage用于表示异步执行过程中的一个步骤Stage,这个步骤可能是由另外一个CompletionStage触发的,随着当前步骤的完成,也可能会触发其他一系列CompletionStage的执行。从而我们可以根据实际业务对这些步骤进行多样化的编排组合,CompletionStage接口正是定义了这样的能力,我们可以通过其提供的thenAppy、thenCompose等函数式编程方法来组合编排这些步骤。

  • CompletableFuture是Future接口的扩展和增强CompletableFuture实现了Future接口,并在此基础上进行了丰富地扩展,完美地弥补了Future上述的种种问题。更为重要的是,
  • CompletableFuture实现了对任务的编排能力。借助这项能力,我们可以轻松地组织不同任务的运行顺序、规则以及方式。从某种程度上说,这项能力是它的核心能力。而在以往,虽然通过CountDownLatch等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护。

2.3 CompletionStage

CompletionStage<T>接口提供了更多方法来更好的实现异步编排,并且大量的使用了JDK8引入的函数式编程概念。由stage执行的计算可以表示为Function,Consumer或Runnable(使用名称分别包括apply 、accept或run的方法 ),具体取决于它是否需要参数和/或产生结果。 例如:

stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println()); 
复制代码

三、使用CompletableFuture场景

3.1 应用场景

1️⃣ 执行比较耗时的操作时,尤其是那些依赖一个或多个远程服务的操作,使用异步任务可以改善程序的性能,加快程序的响应速度;
2️⃣ 使用CompletableFuture类,它提供了异常管理的机制,让你有机会抛出、管理异步任务执行种发生的异常;
3️⃣ 如果这些异步任务之间相互独立,或者他们之间的的某一些的结果是另一些的输入,你可以讲这些异步任务构造或合并成一个。

举个常见的案例🌰,在APP查询首页信息的时候,一般会涉及到不同的RPC远程调用来获取很多用户相关信息数据,比如:商品banner轮播图信息、用户message消息信息、用户权益信息、用户优惠券信息 等,假设每个rpc invoke()耗时是250ms,那么基于同步的方式获取到话,算下来接口的RT至少大于1s,这响应时长对于首页来说是万万不能接受的,因此,我们这种场景就可以通过多线程异步的方式去优化。

3.2 CompletableFuture依赖链分析

根据CompletableFuture依赖数量,可以分为以下几类:零依赖、单依赖、双重依赖和多重依赖

零依赖

下图Future1、Future2都是零依赖的体现:

单依赖:仅依赖于一个CompletableFuture

下图Future3、Future5都是单依赖的体现,分别依赖于Future1Future2

双重依赖:同时依赖于两个CompletableFuture

下图Future4即为双重依赖的体现,同时依赖于Future1Future2

多重依赖:同时依赖于多个CompletableFuture

下图Future6即为多重依赖的体现,同时依赖于Future3Future4Future5

类似这种多重依赖的流程来说,结果依赖于三个步骤:Future3、Future4、Future5,这种多元依赖可以通过allOf()anyOf()方法来实现,区别是当需要多个依赖全部完成时使用allOf(),当多个依赖中的任意一个完成即可时使用anyOf(),如下代码所示:

CompletableFuture<Void> Future6 = CompletableFuture.allOf(Future3, Future4, Future5);
CompletableFuture<String> result = Future6.thenApply(v -> {//这里的join并不会阻塞,因为传给thenApply的函数是在Future3、Future4、Future5全部完成时,才会执行 。result3 = Future3.join();result4 = Future4.join();result5 = Future5.join();// 返回result3、result4、result5组装后结果return assamble(result3, result4, result5);
});
复制代码

四、CompletableFuture异步编排

在分析CompletableFuture异步编排之前,我跟大家理清一下CompletionStage接口下 (thenRun、thenApply、thenAccept、thenCombine、thenCompose)、(handle、whenComplete、exceptionally) 相关方法的实际用法和它们之间的区别是什么? 带着你的想法💭往下看吧!!!

4.1 《异步编排API》

  • thenRun:【执行】直接开启一个异步线程执行任务,不接收任何参数,回调方法没有返回值;
  • thenApply:【提供】可以提供返回值,接收上一个任务的执行结果,作为下一个Future的入参,回调方法是有返回值的;
  • thenAccept:【接收】可以接收上一个任务的执行结果,作为下一个Future的入参,回调方法是没有返回值的;
  • thenCombine:【结合】可以结合不同的Future的返回值,做为下一个Future的入参,回调方法是有返回值的;
  • thenCompose:【组成】将上一个Future实例结果传递给下一个实例中。

✔异步回调建议使用自定义线程池

/*** 线程池配置** @author: austin* @since: 2023/3/12 1:32*/
@Configuration
public class ThreadPoolConfig {/*** @Bean中声明的value不能跟定义的实例同名**/@Bean(value = "customAsyncTaskExecutor")public ThreadPoolTaskExecutor asyncThreadPoolExecutor() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();threadPoolTaskExecutor.setCorePoolSize(5);threadPoolTaskExecutor.setMaxPoolSize(10);threadPoolTaskExecutor.setKeepAliveSeconds(60);threadPoolTaskExecutor.setQueueCapacity(2048);threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);threadPoolTaskExecutor.setThreadNamePrefix("customAsyncTaskExecutor-");threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return threadPoolTaskExecutor;}@Bean(value = "threadPoolExecutor")public ThreadPoolExecutor threadPoolExecutor() {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10000), new ThreadPoolExecutor.CallerRunsPolicy());return threadPoolExecutor;}
}
复制代码

如果所有异步回调都会共用该CommonPool,核心与非核心业务都竞争同一个池中的线程,很容易成为系统瓶颈。手动传递线程池参数可以更方便的调节参数,并且可以给不同的业务分配不同的线程池,以求资源隔离,减少不同业务之间的相互干扰。所以,强烈建议你要根据不同的业务类型创建不同的线程池,以避免互相干扰。通过自定义线程池customAsyncTaskExecutor,后面不同的异步编排方法,我们可以通过指定对应的线程池。

1️⃣ runAsync()、thenRun()

@RestController
public class CompletableFutureCompose {@Resourceprivate ThreadPoolTaskExecutor customAsyncTaskExecutor;@RequestMapping(value = "/thenRun")public void thenRun() {CompletableFuture.runAsync(() -> {System.out.println("thread name:" + Thread.currentThread().getName() + " first step...");}, customAsyncTaskExecutor).thenRun(() -> {System.out.println("thread name:" + Thread.currentThread().getName() + " second step...");}).thenRunAsync(() -> {System.out.println("thread name:" + Thread.currentThread().getName() + " third step...");});}
}
复制代码

接口输出结果:

thread name:customAsyncTaskExecutor-1 first step...
thread name:customAsyncTaskExecutor-1 second step...
thread name:ForkJoinPool.commonPool-worker-3 third step...
复制代码

2️⃣ thenApply()

@RequestMapping(value = "/thenApply")
public void thenApply() {CompletableFuture.supplyAsync(() -> {System.out.println("thread name:" + Thread.currentThread().getName() + " first step...");return "hello";}, customAsyncTaskExecutor).thenApply((result1) -> {String targetResult = result1 + " austin";System.out.println("first step result: " + result1);System.out.println("thread name:" + Thread.currentThread().getName() + " second step..., targetResult: " + targetResult);return targetResult;});
}
复制代码

接口输出结果:

thread name:customAsyncTaskExecutor-2 first step...
first step result: hello
// thenApply虽然没有指定线程池,但是默认是复用它上一个任务的线程池的
thread name:customAsyncTaskExecutor-2 second step..., targetResult: hello austin
复制代码

3️⃣ thenAccept()

@RequestMapping(value = "/thenAccept")
public void thenAccept() {CompletableFuture.supplyAsync(() -> {System.out.println("thread name:" + Thread.currentThread().getName() + " first step...");return "hello";}, customAsyncTaskExecutor).thenAccept((result1) -> {String targetResult = result1 + " austin";System.out.println("first step result: " + result1);System.out.println("thread name:" + Thread.currentThread().getName() + " second step..., targetResult: " + targetResult);});
}
复制代码

接口输出结果:

thread name:customAsyncTaskExecutor-3 first step...
first step result: hello
// thenAccept在没有指定线程池的情况下,并未复用它上一个任务的线程池
thread name:http-nio-10032-exec-9 second step..., targetResult: hello austin
复制代码

thenAccept()thenApply()的用法实际上基本上一致,区别在于thenAccept()回调方法是没有返回值的,而thenApply()回调的带返回值的。

🌈细心的朋友可能会发现,上面thenApply()thenAccept()请求线程池在不指定的情况下,两者的不同表现,thenApply()在不指定线程池的情况下,会沿用上一个Future指定的线程池customAsyncTaskExecutor,而thenAccept()在不指定线程池的情况,并没有复用上一个Future设置的线程池,而是重新创建了新的线程来实现异步调用。

4️⃣ thenCombine()

@RequestMapping(value = "/thenCombine")
public void thenCombine() {CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {System.out.println("执行future1开始...");return "Hello";}, asyncThreadPoolExecutor);CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("执行future2开始...");return "World";}, asyncThreadPoolExecutor);future1.thenCombine(future2, (result1, result2) -> {String result = result1 + " " + result2;System.out.println("获取到future1、future2聚合结果:" + result);return result;}).thenAccept(result -> System.out.println(result));
}
复制代码

接口访问,打印结果:

thread name:customAsyncTaskExecutor-4 执行future1开始...
thread name:customAsyncTaskExecutor-5 执行future2开始...
thread name:http-nio-10032-exec-8 获取到future1、future2聚合结果:Hello World
Hello World
复制代码

5️⃣ thenCompose()

我们先有future1,然后和future2组成一个链:future1 -> future2,然后又组合了future3,形成链:future1 -> future2 -> future3。这里有个隐藏的点:future1、future2、future3它们完全没有数据依赖关系,我们只不过是聚合了它们的结果。

@RequestMapping(value = "/thenCompose")
public void thenCompose() {CompletableFuture.supplyAsync(() -> {// 第一个Future实例结果System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future1开始...");return "Hello";}, customAsyncTaskExecutor).thenCompose(result1 -> CompletableFuture.supplyAsync(() -> {// 将上一个Future实例结果传到这里System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future2开始..., 第一个实例结果:" + result1);return result1 + " World";})).thenCompose(result12 -> CompletableFuture.supplyAsync(() -> {// 将第一个和第二个实例结果传到这里System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future3开始..., 第一第二个实现聚合结果:" + result12);String targetResult = result12 + ", I am austin!";System.out.println("最终输出结果:" + targetResult);return targetResult;}));
}
复制代码

接口访问,打印结果:

thread name:customAsyncTaskExecutor-1 执行future1开始...
thread name:ForkJoinPool.commonPool-worker-3 执行future2开始..., 第一个实例结果:Hello
thread name:ForkJoinPool.commonPool-worker-3 执行future3开始..., 第一第二个实现聚合结果:Hello World
最终输出结果:Hello World, I am austin!
复制代码

💥Note:thenCombine() VS thenCompose(),两者之间的区别

  • thenCombine结合的两个CompletableFuture没有依赖关系,且第二个CompletableFuture不需要等第一个CompletableFuture执行完成才开始。
  • thenCompose() 可以两个 CompletableFuture 对象,并将前一个任务的返回结果作为下一个任务的参数,它们之间存在着先后顺序。
  • thenCombine() 会在两个任务都执行完成后,把两个任务的结果合并。两个任务是并行执行的,它们之间并没有先后依赖顺序。

4.2 《CompletableFuture实例化创建》

// 返回一个新的CompletableFuture,由线程池ForkJoinPool.commonPool()中运行的任务异步完成,不会返回结果。
public static CompletableFuture<Void> runAsync(Runnable runnable);
// 返回一个新的CompletableFuture,运行任务时可以指定自定义线程池来实现异步,不会返回结果。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);// 返回由线程池ForkJoinPool.commonPool()中运行的任务异步完成的新CompletableFuture,可以返回异步线程执行之后的结果。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
复制代码

CompletableFuture有两种方式实现异步,一种是supply开头的方法,一种是run开头的方法:

  • supply 开头:该方法可以返回异步线程执行之后的结果;
  • run 开头:该方法不会返回结果,就只是执行线程任务。

4.3 《获取CompletableFuture结果》

public  T   get()
public  T   get(long timeout, TimeUnit unit)
public  T   getNow(T valueIfAbsent)
public  T   join()
public CompletableFuture<Object> allOf()
public CompletableFuture<Object> anyOf()
复制代码

使用方式,演示🌰:

CompletableFuture<Integer> future = new CompletableFuture<>();
Integer integer = future.get();
复制代码
  • get()阻塞式获取执行结果,如果任务还没有完成则会阻塞等待知直到任务执行完成
  • get(long timeout, TimeUnit unit):带超时的阻塞式获取执行结果
  • getNow():如果已完成,立刻返回执行结果,否则返回给定的valueIfAbsent
  • join():该方法和get()方法作用一样, 不抛异常的阻塞式获取异步执行结果
  • allOf():当给定的所有CompletableFuture都完成时,返回一个新的CompletableFuture
  • anyOf():当给定的其中一个CompletableFuture完成时,返回一个新的CompletableFuture

💥Note:

  • join()get()方法都是 阻塞式 调用它们的线程(通常为主线程)来获取CompletableFuture异步之后的返回值。
  • 两者的区别在于join()返回计算的结果或者抛出一个unchecked异常CompletionException,而get()返回一个具体的异常。

4.4 《结果处理》

当使用CompletableFuture异步调用计算结果完成、或者是抛出异常的时候,我们可以执行特定的Action做进一步处理,比如:

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
复制代码

4.5 《异常处理》

使用CompletableFuture编写代码时,异常处理很重要,CompletableFuture提供了三种方法来处理它们:handle()、whenComplete() 和 exceptionly()

  • handle:返回一个新的CompletionStage,当该阶段正常或异常完成时,将使用此阶段的结果和异常作为所提供函数的参数执行,不会将内部异常抛出
  • whenComplete:返回与此阶段具有相同结果或异常的新CompletionStage,该阶段在此阶段完成时执行给定操作。与方法handle不同,会将内部异常往外抛出
  • exceptionally:返回一个新的CompletableFutureCompletableFuture提供了异常捕获回调exceptionally,相当于同步调用中的try/catch
@Autowired
private RemoteDictService remoteDictService;public CompletableFuture<Dict> getDictDataAsync(long dictId) {CompletableFuture<DictResult> resultFuture = remoteDictService.findDictById(dictId);// 业务方法,内部会发起异步rpc调用return resultFuture.exceptionally(error -> {//通过exceptionally捕获异常,打印日志并返回默认值log.error("RemoteDictService.getDictDataAsync Exception dictId = {}", dictId, error);return null;});
}
复制代码

handle() VS whenComplete(), 两者之间的区别

  • 💥💥💥核心区别在于whenComplete不消费异常,而handle消费异常

Two method forms support processing whether the triggering stage completed normally or exceptionally:

Method {whenComplete} allows injection of an action regardless of outcome, otherwise preserving the outcome in its completion.

Method {handle} additionally allows the stage to compute a replacement result that may enable further processing by other dependent stages.

翻译过来就是:

两种方法形式支持处理触发阶段是否 正常完成 或 异常完成:

  • whenComplete:可以访问当前CompletableFuture结果异常 作为参数,使用它们并执行您想要的操作。此方法并不能转换完成的结果,会内部抛出异常
  • handle:当此阶段正常或异常完成时,将使用此阶段的结果和异常作为所提供函数的参数来执行。当此阶段完成时,以 该阶段的结果该阶段的异常 作为参数调用给定函数,并且函数的结果用于完成返回的阶段,不会把异常外抛出来

这里我通过代码演示一下:

public class CompletableFutureExceptionHandler {public static CompletableFuture handle(int a, int b) {return CompletableFuture.supplyAsync(() -> a / b).handle((result, ex) -> {if (null != ex) {System.out.println("handle error: " + ex.getMessage());return 0;} else {return result;}});}public static CompletableFuture whenComplete(int a, int b) {return CompletableFuture.supplyAsync(() -> a / b).whenComplete((result, ex) -> {if (null != ex) {System.out.println("whenComplete error: " + ex.getMessage());}});}public static void main(String[] args) {try {System.out.println("success: " + handle(10, 5).get());System.out.println("fail: " + handle(10, 0).get());} catch (Exception e) {System.out.println("catch exception= " + e.getMessage());}System.out.println("------------------------------------------------------------------");try {System.out.println("success: " + whenComplete(10, 5).get());System.out.println("fail: " + whenComplete(10, 0).get());} catch (Exception e) {System.out.println("catch exception=" + e.getMessage());}}
}
复制代码

运行结果如下显示

success: 2
handle error: java.lang.ArithmeticException: / by zero
fail: 0
------------------------------------------------------------------
success: 2
whenComplete error: java.lang.ArithmeticException: / by zero
catch exception=java.lang.ArithmeticException: / by zero
复制代码

✔可以看到,handle处理,当程序发生异常的时候,即便是catch获取异常期望输出,但是并未跟实际预想那样,原因是handle不会把内部异常外抛出来,而whenComplete会将内部异常抛出。

五、CompletableFuture线程池须知

🔥Note:关于异步线程池(十分重要)

异步回调方法可以选择是否传递线程池参数Executor,这里为了实现线程池隔离,当不传递线程池时,默认会使用ForkJoinPool中的公共线程池CommonPool,这个线程池默认创建的线程数是CPU的核数,如果所有的异步回调共享一个线程池,核心与非核心业务都竞争同一个池中的线程,那么一旦有任务执行一些很慢的I/O 操作,就会导致线程池中所有线程都阻塞在I/O操作上,很容易成为系统瓶颈,影响整个系统的性能。因此,💥💥 建议强制传线程池,且根据实际情况做线程池隔离,减少不同业务之间的相互干扰

六、基于CompletableFuture实现接口异步revoke

案例实现Controller层

@RestController
@RequestMapping("/index")
public class IndexWebController {@Resourceprivate ThreadPoolExecutor asyncThreadPoolExecutor;@RequestMapping(value = "/homeIndex", method = {RequestMethod.POST, RequestMethod.GET})public String homeIndex(@RequestParam(required = false) String userId, @RequestParam(value = "lang") String lang) {ResultData<HomeVO> result = new ResultData<>();// 获取Banner轮播图信息CompletableFuture<List<BannerVO>> future1 = CompletableFuture.supplyAsync(() -> this.buildBanners(userId, lang), asyncThreadPoolExecutor);// 获取用户message通知信息CompletableFuture<NotificationVO> future2 = CompletableFuture.supplyAsync(() -> this.buildNotifications(userId, lang), asyncThreadPoolExecutor);// 获取用户权益信息CompletableFuture<List<BenefitVO>> future3 = CompletableFuture.supplyAsync(() -> this.buildBenefits(userId, lang), asyncThreadPoolExecutor);// 获取优惠券信息CompletableFuture<List<CouponVO>> future4 = CompletableFuture.supplyAsync(() -> this.buildCoupons(userId), asyncThreadPoolExecutor);CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(futrue1, futrue2, futrue3, future4);HomeVo finalHomeVO = homeVO;CompletableFuture<HomeVO> resultFuture = allOfFuture.thenApply(v -> {try {finalHomeVo.setBanners(future1.get());finalHomeVo.setNotifications(future2.get());finalHomeVo.setBenefits(future3.get());finalHomeVo.setCoupons(future4.get());return finalHomeVO;} catch (Exception e) {logger.error("[Error] assemble homeVO data error: {}", e);throw new RuntimeException(e);}});homeVO = resultFuture.join();result.setData(homeVO);return writeJson(result);}
}
复制代码

Service层

@SneakyThrows
public List<BannerVO> buildBanners(String userId, String lang) {// 模拟请求耗时0.5秒Thread.sleep(500);return new List<BannerVO>();
}@SneakyThrows
public List<NotificationVO> buildNotifications(String userId, String lang) {// 模拟请求耗时0.5秒Thread.sleep(500);return new List<NotificationVO>();
}@SneakyThrows
public List<BenefitVO> buildBenefits(String userId, String lang) {// 模拟请求耗时0.5秒Thread.sleep(500);return new List<BenefitVO>();
}@SneakyThrows
public List<CouponVO> buildCoupons(String userId) {// 模拟请求耗时0.5秒Thread.sleep(500);return new List<CouponVO>();
}
复制代码

六、异步化带来的性能提升

  • 通过异步化改造,原本同步获取数据的API性能得到明显提升,大大减少了接口的响应时长(RT)。
  • 接口的吞吐量大幅度提升。

七、总结

本篇文章主要是介绍了CompletableFuture使用原理和相关不同方法的场景化使用,以及通过不同的实例演示了异步回调的过程,好了,今天的分享就到此结束了,如果文章对你有所帮助,欢迎 点赞👍+评论💬+收藏❤


http://chatgpt.dhexx.cn/article/DS4tIfXF.shtml

相关文章

【Java8新特性--->异步处理】CompletableFuture

一、引入 假设一个商品详情页需要以下操作&#xff1a; 查询展示商品的基本信息耗时&#xff1a;0.5s查询展示商品的销售信息耗时&#xff1a;0.7s查询展示商品的图片信息耗时&#xff1a;1s查询展示商品销售属性耗时&#xff1a;0.3s查询展示商品规格属性耗时&#xff1a;1.…

CompletableFuture API

目录 1. 为什么要用CompletableFuture1.1 API 2. CompletableFuture Demo1. 创建CompletableFuture2. 定义CompletableFuture完成时和异常时需要回调的实例3. CompletableFuture的优点 3. demo&#xff1a;多个CompletableFuture串行执行4. demo&#xff1a;多个CompletableFut…

CompletableFuture实战与分析

Future对于结果的获取不够好&#xff0c;只能通过阻塞或者轮询的方式得到任务的结果。在Java8中Doug Lea大师提供了一个CompletableFuture工具类&#xff0c;可以更优雅的对异步并行操作进行编排。 Future VS CompletableFuture CompletableFuture支持手动完成任务&#xff0…

Java8 CompletableFuture异步非阻塞做法

创建异步任务 Future.submit supplyAsync / runAsync 异步回调 thenApply / thenApplyAsync thenAccept / thenRun exceptionally whenComplete handle 组合处理 thenCombine / thenAcceptBoth / runAfterBoth applyToEither / acceptEither / runAfterEither thenCom…

2022.2.5 第十三次周报

文章目录 前言一、论文阅读《ROCKET: Exceptionally fast and accurate time series classification using random convolutional kernels》Abstract摘要Introduction介绍Method方法Kernels内核Transform转换Classifier分类器Complexity Analysis复杂性分析 Experiments实验Con…

并发编程(十五)-CompletableFuture中常用方法的使用与分析

文章目录 一、CompletableFuture API介绍1. 描述2. CompletionStage3. CompletableFuture 4个核心静态方法&#xff08;1&#xff09;runAsync(Runnable runnable)&#xff08;2&#xff09;runAsync(Runnable runnable, Executor executor)&#xff08;3&#xff09;supplyAsy…

Java 编程问题:十一、并发-深入探索

原文&#xff1a;Java Coding Problems 协议&#xff1a;CC BY-NC-SA 4.0 贡献者&#xff1a;飞龙 本文来自【ApacheCN Java 译文集】&#xff0c;自豪地采用谷歌翻译。 本章包括涉及 Java 并发的 13 个问题&#xff0c;涉及 Fork/Join 框架、CompletableFuture、ReentrantLock…

线程(十二)---CompletableFuture(三)

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01; 示例五&#xff1a;异常处理 接着上一篇记录一下CompletableFuture的异常处理&#xff0c;异常处理通常使用…

dice loss

Dice Loss 最先是在VNet 这篇文章中被提出&#xff0c;后来被广泛的应用在了医学影像分割之中。 Dice 系数 Dice系数作为损失函数的原因和混淆矩阵有着很大的关系&#xff0c;下图给出的是一个混淆矩阵&#xff1a; 其中的一些关键指标如下&#xff1a; 精确率(precision)表…

Hinge loss

声明&#xff1a; 参考自维基百科后面可能会更新 Hinge Loss 在机器学习中&#xff0c;hinge loss作为一个损失函数(loss function)&#xff0c;通常被用于最大间隔算法(maximum-margin)&#xff0c;而最大间隔算法又是SVM(支持向量机support vector machines)用到的重要算法…

【深度学习】一文读懂机器学习常用损失函数(Loss Function)

【深度学习】一文读懂机器学习常用损失函数&#xff08;Loss Function&#xff09; 最近太忙已经好久没有写博客了&#xff0c;今天整理分享一篇关于损失函数的文章吧&#xff0c;以前对损失函数的理解不够深入&#xff0c;没有真正理解每个损失函数的特点以及应用范围&#x…

Pytorch之loss(损失函数)

损失函数也在torch.nn下&#xff0c;具体可以参考文档&#xff0c;也可以参考官网 先根据L1Loss举例 我个人感觉这里的描述还是到官网的文档找比较好&#xff0c;公式看的比文档清楚 import torch from torch import nninputs torch.tensor([[3, 2, 1],[1, 2, 3]], dtypetorch…

机器学习 损失函数 Loss function

损失函数 最小二乘法极大似然估计法交叉熵 【本文根据B站-王木头学科学-视频所学】 在梯度下降中&#xff0c;所求的梯度其实就是损失函数的梯度。 损失函数有三种设计方法&#xff1a; &#xff08;1&#xff09;最小二乘法 &#xff08;2&#xff09;极大似然估计法 &#x…

Focal loss 损失函数详解

Focal loss 目前目标检测的算法大致分为两类&#xff0c;One Stage 、Two Stage。 One Stage&#xff1a;主要指类似YOLO、SGD等这样不需要region proposal,直接回归的检测算法&#xff0c;这类算法检测速度很快&#xff0c;但是精度准确率不如使用Two stage的模型。 two St…

机器学习之常见的损失函数(loss function)

解决一个机器学习问题主要有两部分&#xff1a;数据和算法。而算法又有三个部分组成&#xff1a;假设函数、损失函数、算法优化。我们一般在看算法书或者视频教学时&#xff0c;更多的是去推算或者说参数估计出其假设函数&#xff0c;而往往不太注重损失函数&#xff0c;但是损…

深度学习loss函数理解

机器学习中的范数规则化之L0、L1、L2范数及loss函数 监督机器学习问题无非就是“minimizeyour error while regularizing your parameters”&#xff0c;也就是在规则化参数的同时最小化误差。 最小化误差是为了让我们的模型拟合我们的训练数据&#xff0c;而规则化参数是防止我…

CE Loss,BCE Loss以及Focal Loss的原理理解

一、交叉熵损失函数&#xff08;CE Loss&#xff0c;BCE Loss&#xff09; 最开始理解交叉熵损失函数被自己搞的晕头转向的&#xff0c;最后发现是对随机变量的理解有偏差&#xff0c;不知道有没有读者和我有着一样的困惑&#xff0c;所以在本文开始之前&#xff0c;先介绍一下…

损失函数loss

http://blog.csdn.net/pipisorry/article/details/23538535 监督学习及其目标函数 损失函数&#xff08;loss function&#xff09;是用来估量你模型的预测值f(x)与真实值Y的不一致程度&#xff0c;它是一个非负实值函数&#xff0c;通常使用L(Y, f(x))来表示。 损失函数是经…

机器学习模型中的损失函数loss function

1. 概述 在机器学习算法中&#xff0c;有一个重要的概念就是损失函数&#xff08;Loss Function&#xff09;。损失函数的作用就是度量模型的预测值 f ( x ) f\left ( \mathbf{x} \right ) f(x)与真实值 y \mathbf{y} y之间的差异程度的函数&#xff0c;且是一个非负实值函数。…

损失函数(Loss)

如果我们定义了一个机器学习模型&#xff0c;比如一个三层的神经网络&#xff0c;那么就需要使得这个模型能够尽可能拟合所提供的训练数据。但是我们如何评价模型对于数据的拟合是否足够呢&#xff1f;那就需要使用相应的指标来评价它的拟合程度&#xff0c;所使用到的函数就称…