异步利刃CompletableFuture

简介: 异步利刃CompletableFuture

什么是CompletableFuture?

CompletableFuture 类实现了 Future 和 CompletionStage 接口并且新增了许多方法,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。简单来说可以帮我们实现任务编排。【文中所有代码已上传码云

CompletableFuture的创建

先来看一个创建例子,后续再展开说说这个类中的方法:

CompletableFuture<String>completableFuture=newCompletableFuture<>();
completableFuture.complete("Hello CompletableFuture");
System.out.println(completableFuture.get());

需要注意的是当我们对不完整的 CompleteableFuture调用 get 方法的话,会由于 Future 未完成,因此 get 调用会一直阻塞。

创建异步任务

CompletableFuture 提供了四个静态方法来创建异步任务。

publicstatic<U>CompletableFuture<U>supplyAsync(Supplier<U>supplier);
publicstatic<U>CompletableFuture<U>supplyAsync(Supplier<U>supplier, Executorexecutor);
publicstaticCompletableFuture<Void>runAsync(Runnablerunnable);
publicstaticCompletableFuture<Void>runAsync(Runnablerunnable, Executorexecutor);

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码;如果指定线程池,则使用指定的线程池运行。

staticExecutorscreenExecutor(Executore) {
if (!useCommonPool&&e==ForkJoinPool.commonPool())
returnasyncPool;
if (e==null) thrownewNullPointerException();
returne;
    }

二者的区别很明显,supplyAsync有返回值,runAsync方法无返回值。我们通过静态方法会立刻开启异步线程执行Supplier或者Runnable提交的任务。任务执行完成,就可以打印返回值,不再需要其它线程主动调用complete来表示任务执行完成。

获取任务执行结果

publicTget();
publicTget(longtimeout, TimeUnitunit);
publicTgetNow(TvalueIfAbsent);
publicTjoin();

get()和get(long timeout, TimeUnit unit)是实现了Future接口的功能,两者主要区别就是get()会一直阻塞直到获取到结果,get(long timeout, TimeUnit unit)值可以指定超时时间,当到了指定的时间还未获取到任务,就会抛出TimeoutException异常。

getNow(T valueIfAbsent):就是获取任务的执行结果,但不会产生阻塞。如果任务还没执行完成,那么就会返回你传入的 valueIfAbsent 参数值,如果执行完成了,就会返回任务执行的结果。

join():跟get()的主要区别就是,get()会抛出检查时异常,join()不会。

任务完成后的处理

whenComplete

publicCompletableFuture<T>whenComplete(BiConsumer<?superT,?superThrowable>action)
publicCompletableFuture<T>whenCompleteAsync(BiConsumer<?superT,?superThrowable>action)
publicCompletableFuture<T>whenCompleteAsync(BiConsumer<?superT,?superThrowable>action, Executorexecutor)
publicCompletableFuture<T>exceptionally(Function<Throwable,?extendsT>fn)

whenComplete是等任务完成后继续执行whenComplete的action,这里也能看出执行action的是主线程

如果有异常,当主线程在获取任务结果时就会抛出异常。

而whenCompleteAsync是通过异步线程去执行action

exceptionally

任务执行过程中出现异常的时候,会回调exceptionally方法指定的回调,但是如果没有出现异常,是不会回调的。

thenApply

当线程B依赖于线程A的执行结果时,可以使用thenApply方法来把这两个线程串行化

public<U>CompletableFuture<U>thenApply(Function<?superT,?extendsU>fn)
public<U>CompletableFuture<U>thenApplyAsync(Function<?superT,?extendsU>fn)
public<U>CompletableFuture<U>thenApplyAsync(Function<?superT,?extendsU>fn, Executorexecutor)

将supplyAsync方法里的结果(Integer)作为thenApply方法里Function接口的apply方法的入参

如果有异常thenApply就不会执行

handle

public<U>CompletionStage<U>handle(BiFunction<?superT, Throwable, ?extendsU>fn);
public<U>CompletionStage<U>handleAsync(BiFunction<?superT, Throwable, ?extendsU>fn);
public<U>CompletionStage<U>handleAsync(BiFunction<?superT, Throwable, ?extendsU>fn,Executorexecutor);

不同于thenApply的是handle里的方法是在supplyAsync/runAsync执行后一定会执行。

thenAccept

publicCompletionStage<Void>thenAccept(Consumer<?superT>action);
publicCompletionStage<Void>thenAcceptAsync(Consumer<?superT>action);
publicCompletionStage<Void>thenAcceptAsync(Consumer<?superT>action,Executorexecutor);

不同于上述的方法,thenAccept纯消费无返回值。

组合任务

thenCompose

这个方法也是线程B需要用到线程A的结果,不同于thenApply的是:thenCompose()用来连接两个CompletableFuture,返回值是新的CompletableFuture;thenApply()转换的是泛型中的类型,是同一个CompletableFuture。

public<U>CompletableFuture<U>thenCompose(Function<?superT,?extendsCompletionStage<U>>fn)
public<U>CompletableFuture<U>thenComposeAsync(Function<?superT,?extendsCompletionStage<U>>fn)
public<U>CompletableFuture<U>thenComposeAsync(Function<?superT,?extendsCompletionStage<U>>fn, Executorexecutor)

thenCombine

会把两个CompletableFuture的任务都执行完成后把结果一块交给thenCombine来处理,并生成新的CompletableFuture任务。

public<U,V>CompletionStage<V>thenCombine(CompletionStage<?extendsU>other,BiFunction<?superT,?superU,?extendsV>fn);
public<U,V>CompletionStage<V>thenCombineAsync(CompletionStage<?extendsU>other,BiFunction<?superT,?superU,?extendsV>fn);
public<U,V>CompletionStage<V>thenCombineAsync(CompletionStage<?extendsU>other,BiFunction<?superT,?superU,?extendsV>fn,Executorexecutor);

谁调用的thenCombine,则BiFunction的第一个参数就是它的结果。

其他方法

allOf

allOf方法的入参是多个CompletableFuture任务,返回类型是CompletableFuture<Void>,allOf方法是等所有的CompletableFuture都执行完后再执行计算,一般后面会跟链式的thenApply方法或者thenAccept方法对所有的异步任务进行汇总处理。

anyOf

anyOf方法入参也是多个CompletableFuture任务,返回类型是CompletableFuture<Object>,anyOf方法只要有一个CompletableFuture任务完后就执行。

相关文章
|
5天前
|
Java
异步技巧之CompletableFuture
异步技巧之CompletableFuture
44 2
|
5天前
|
并行计算 Java
异步编程好帮手之CompletableFuture详解
异步编程好帮手之CompletableFuture详解
39 0
|
5天前
|
前端开发 Java API
Java并发基础:CompletableFuture全面解析
CompletableFuture类使得并发任务的处理变得简单而高效,通过简洁的API,开发者能轻松创建、组合和链式调用异步操作,无需关心底层线程管理,这不仅提升了程序的响应速度,还优化了资源利用率,让复杂的并发逻辑变得易于掌控。
102 1
Java并发基础:CompletableFuture全面解析
|
5天前
|
监控 安全 Java
CompletableFuture探秘:解锁Java并发编程的新境界
CompletableFuture探秘:解锁Java并发编程的新境界
143 0
|
5天前
|
前端开发 JavaScript Java
每日一博 - Java 异步编程的 Promise 模式 CompletableFuture的前世今生 (上)
每日一博 - Java 异步编程的 Promise 模式 CompletableFuture的前世今生 (上)
71 0
每日一博 - Java 异步编程的 Promise 模式 CompletableFuture的前世今生 (上)
|
7月前
|
存储 Dubbo Java
JUC第二十五讲:JUC线程池-CompletableFuture 实现原理与实践
JUC第二十五讲:JUC线程池-CompletableFuture 实现原理与实践
|
8月前
|
消息中间件 存储 Java
一网打尽异步神器CompletableFuture
最近一直畅游在RocketMQ的源码中,发现在RocketMQ中很多地方都使用到了CompletableFuture,所以今天就跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,并且最后会结合RocketMQ源码分析一下CompletableFuture的使用。
|
8月前
|
机器人 测试技术 调度
异步大作战:协程、await、asyncio 浅尝
嘿,帅气的小伙!今天,咱们简单聊聊那些看似高级却又神秘莫测的异步编程技巧,俗称“协程”和“async/await
|
12月前
|
Java API 调度
【并发编程】异步编程CompletableFuture实战
【并发编程】异步编程CompletableFuture实战
【并发编程】异步编程CompletableFuture实战
|
消息中间件 JavaScript 小程序
一网打尽:异步神器 CompletableFuture 万字详解!
一网打尽:异步神器 CompletableFuture 万字详解!