异步利刃CompletableFuture

news/2024/10/27 20:36:58/

什么是CompletableFuture?

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

CompletableFuture的创建

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

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

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

创建异步任务

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

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);

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

    static Executor screenExecutor(Executor e) {if (!useCommonPool && e == ForkJoinPool.commonPool())return asyncPool;if (e == null) throw new NullPointerException();return e;}

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

获取任务执行结果

public T get();
public T get(long timeout, TimeUnit unit);
public T getNow(T valueIfAbsent);
public T join();

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

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

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

任务完成后的处理

whenComplete

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)
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)

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

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

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

exceptionally

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

thenApply

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

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

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

如果有异常thenApply就不会执行

handle

public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

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

thenAccept

public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);

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

组合任务

thenCompose

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

public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor)

thenCombine

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

public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);

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

其他方法

allOf

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

anyOf

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


http://www.ppmy.cn/news/144405.html

相关文章

保护密码安全:ADSelfService Plus的重要性与优势

引言&#xff1a; 在当今数字化时代&#xff0c;密码安全对于个人和组织而言变得愈发重要。随着互联网的普及和数据泄露事件的频发&#xff0c;传统的用户名和密码已经不再足够保护我们的个人和机密信息。为了解决这个问题&#xff0c;许多组织开始采用密码管理工具&#xff0…

19c rac部署-ssh版本太高的问题

客户有个环境需要部署19c&#xff0c;安装的oracle linux 7.9.&#xff0c;OpenSSH_7.4p1版本适合安装19c集群&#xff0c;但接到环境时&#xff0c;发现openssh已升级到9.0了&#xff0c;理由是等保需要&#xff0c;哎&#xff0c;不抱怨自己解决问题 [INS-32070] Could not r…

得力打卡机表格破解密码

表格密码&#xff1a;AAABABBBBAA3 或 AAAABBAABBBO

【求助】钉钉打卡机导出的考勤表上下班同格,怎么统计?

姓名在打卡时间不同行&#xff0c;打卡时间上下班时间同格&#xff0c;要怎么统计&#xff0c;求各路大神指教

打卡机之生成校验码

打卡机之生成校验码 应市场需求&#xff0c;某工程师现设计了一款新上下班打卡机&#xff0c;打卡机具有以下功能&#xff1a; &#xff08;1&#xff09; 上班打卡&#xff0c;员工具有编号&#xff08;首位为1 的六位编号&#xff09;&#xff0c;输入编号后&#xff0c;再 …

什么是DDI?DDI有哪些作用和优势?(中科三方)

随着大数据、物联网、AI等新技术的快速发展&#xff0c;网络设备对IP地址资源的需求呈爆炸式指数级增长&#xff0c;传统的IP管理模式已经无法满足大规模复杂化的网络环境&#xff0c;网络可用性和服务质量下降&#xff0c;对各行业线上业务的开展形成了严重掣肘。政府机关、国…

打卡机居然被调慢了10分钟

NND&#xff0c;今天早上公车每遇十字路口就必遇到红灯&#xff0c;每站上车的人仿佛也出奇的多&#xff0c;比平时足足多花了10分钟。原以为非迟到不可&#xff0c;打卡机居然调慢了10分钟&#xff0c;没想到啊&#xff01; 来自 “ ITPUB博客 ” &#xff0c;链接&#xff1a…

内丘计算机学校,内丘学校食堂打卡机

学校食堂打f2e31d卡机内丘。指纹考勤机超过几百人使用时&#xff0c;处理时间较其它打卡方式慢数倍。同时在静电干扰、汗液盐分、其它赃物、手指磨损、贴*角度或压力不当时&#xff0c;采集头很难读取指纹&#xff0c;轻者识别效率低&#xff0c;重者识别失败。虹膜考勤机则受到…