广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java中CompletableFuture 的详细介绍
  • 631
分享到

Java中CompletableFuture 的详细介绍

2024-04-02 19:04:59 631人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录1.概述1.0 创建 CompletableFuture 的对象的工厂方法1.1 non-async 和 async 区别1.1.1 non-async 示例:注册 action

1.概述

1.0 创建 CompletableFuture 的对象的工厂方法

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

runAsync 的参数是 Runnable, 返回值是 CompletableFuture, 意思是工厂方法创建的 CompletableFuture 对象封装的任务没有返回值。

例如:

CompletableFuture<Void> run = CompletableFuture.runAsync(()-> System.out.println("hello"));

而 suppyAsync 参数类型是 Supplier,返回值是CompletableFuture<U> , 意思是任务不接受参数,但是会返回结果。

CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
    System.out.println("Hello");
    return "hello world!"";
});
System.out.println(supply.get());  //hello world!"

所以如果任务需要返回结果,那么应该选择 suppyAsync;否则可以选择 runAsync。

1.1 non-async 和 async 区别

public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);

CompletableFuture 中有众多类似这样的方法,那么 non-async 和 async 和版本的方法究竟有什么区别呢? 参考官方文档的描述:

Actions supplied for dependent completions of non-async methods may be perfORMed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.

翻译:传递给 non-async 方法作为参数的函数(action)可能会在完成当前的 CompletableFuture 的线程中执行,也可能会在方法的调用者线程中执行。

All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interface CompletableFuture.AsynchronousCompletionTask.

翻译:所有没有Executor 参数的 async 方法都在 ForkJoinPool.commonPool()线程池中执行(除非不支持最小并发度为2,这种情况下,每个任务会创建一个新线程去执行)。为了简化监控、调试和追踪,所有生成的异步任务都是接口 CompletableFuture.AsynchronousCompletionTask的实例。

从上面这两段官方描述看。async 类方法比较容易理解,就是 CompletableFuture 实例的任务执行完成后,会将 action 提交到缺省的异步线程池 ForkJoinPool.commonPool(),或者 async 类方法参数Executor executor 指定的线程池中执行。

而对于 non-async 的描述则有点不明确。action 可能会在完成 CompletableFuture 实例任务的线程中执行,也可能会在调用 thenRun(编排任务完成后执行 action 的系列方法) 方法的线程中执行。这个主要是看调用 thenRun 的时候,CompletableFuture 实例的任务是否已经完成。如果没有完成,那么action 会在完成任务的线程中执行。如果任务已经完成,则 action 会在调用thenAccept 等注册方法的线程中执行

1.1.1 non-async 示例:注册 action 的时候任务可能已经结束

@Test
void testThenRunWithTaskCompleted() throws Exception{
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            System.out.println("[" + Thread.currentThread().getName() + "] " + " in task" );
            return 1;
        }
    }).thenRun(() -> {
        System.out.println("[" + Thread.currentThread().getName() + "] " + " in action" );
    });
    future.get();
}

运行结果:

[ForkJoinPool.commonPool-worker-1]  in task
[main]  in action

分析: 任务通过 CompletableFuture.supplyAsync 提交后,会以异步的方式在 ForkJoinPool.commonPool() 线程池中运行。这时候有两个线程,一个是[ForkJoinPool.commonPool-worker-1] 执行 Supplier.get 方法;一个是[main] 主线程提交完异步任务后,继续调用 thenRun 编排任务完成后执行 action。由于Supplier.get 非常简单,几乎立刻返回。所以很大概率在主线程调用 thenRun 编排任务完成后执行 action的时候,异步任务已经完成,所以 action 在主线程中执行了。注:在笔者的电脑上几乎100% 是这样的调度方式。

1.1.2 non-async 示例:注册 action 的时候任务未完成

@Test
void testThenRunWithTaskUncompleted() throws Exception{
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            System.out.println("[" + Thread.currentThread().getName() + "] " + " in task" );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new Random().nextInt(10);
        }
    }).thenRun(() -> {
        System.out.println("[" + Thread.currentThread().getName() + "] " + " in action" );
    });
    future.get();
}

运行结果:

[ForkJoinPool.commonPool-worker-1]  in task
[ForkJoinPool.commonPool-worker-1]  in action

分析:在 Supplier.get 加入 sleep,延迟任务结束。主线程提交完异步任务后,继续调用 thenRun 编排任务完成后执行 action 的时候,任务没有结束。所以这个action 在完成任务的线程中执行。

1.2 Run 类方法

Run 类方法指 thenRun、runAfterBoth、runAfterEither 等。Run 类方法的动作参数都是Runable action。例如 thenRun(Runnable action)。这就意味着这个 action 不关心任务的结果,action 本身也没有返回值。只是为了实现在完成任务后执行一个动作的目的

1.3 Accept 类方法

Accept 类方法指 thenAccept、runAcceptBoth、runAcceptEither 等。Accept 类方法的动作参数都是Consumer<? super T> action。例如 thenAccept(Consumer<? super T> action)。如方法名和参数所示,action 是接受并消费任务结果的消费者,action 没有返回值

1.4 Apply 类方法

Apply 类方法指 thenApply、applyToEither 等。Apply 类方法的动作参数都是Function<? super T,? extends U> fn。例如 thenApply(Function<? super T,? extends U> fn)。如方法名和参数所示,action 将任务结果应用函数参数 fn 做转换,返回转换后的结果,类似于 stream 中的 map

2 单个任务执行完成后执行一个动作(action)

方法说明
public CompletableFuture<Void> thenRun(Runnable action)
thenRunAsync(Runnable action)
thenRunAsync(Runnable action, Executor executor)
任务完成后执行 action,action 中不关心任务的结果,action 也没有返回值
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
thenAcceptAsync(Consumer<? super T> action)
thenAcceptAsync(Consumer<? super T> action)
任务完成后执行 action。如方法名和参数所示,action 是接受并消费任务结果的消费者,action 没有返回值
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
thenApplyAsync(Function<? super T,? extends U> fn)
thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
任务完成后执行 action。action 将任务结果应用 action 的函数参数做转换,返回转换后的结果,类似于 stream 中的 map
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
任务完成后或者异常时运行action。action 是接受并消费任务结果的消费者,并且有返回值。可以认为是支持异常处理的 thenAccept 版本。
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)
handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
任务完成后或者异常时运行action。可以认为是支持异常处理的 thenApply 版本。
public CompletableFuture exceptionally(Function<Throwable, ? extends T> fn)如果任务或者 action 发生异常,则会触发exceptionally的调用相当于 try...catch

2.0 示例 exceptionally

@Test
void testCompletableFutureExceptionally(){
    CompletableFuture<Integer> first = CompletableFuture
            .supplyAsync(() -> {
                if (true) {
                    throw new RuntimeException("exception in task");
                }
                return "hello world";
            })
            .thenApply(data -> {
                if (true) {
                    throw new RuntimeException("exception in action");
                }
                return 1;
            })
            .exceptionally(e -> {
                System.out.println("[" + Thread.currentThread().getName() + "] " + " print exception stack trace" );
                e.printStackTrace(); // 异常捕捉处理,前面两个处理环节的日常都能捕获
                return 0;
            });
}

3 两个任务执行编排

下面表格列出的每个方法都有对应两个版本的 async 方法,一个有executor 参数,一个没有。为了表格尽量简洁,表格中就不再列出async 方法了

方法说明
public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage> fn)串行组合两个 CompletableFuture 任务,后一个任务依赖前一个任务的结果,后一个任务可以返回与第一个任务不同类型的返回值。执行后一个任务的线程与前面讨论 action 执行的线程类似。
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)这里有两个并行任务,一个是runAfterBoth 调用本身所属的CompletableFuture 实例A,一个是参数 other 引用的任务B。两个并行任务都完成后执行 action,action 中不关心任务的结果,action 也没有返回值
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)与runAfterBoth 类似,也有两个并行任务 A 和 B。两个并行任务都完成后执行 action。如方法名和参数所示,action 是接受并消费两个任务结果的消费者,action 没有返回值
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)与runAfterBoth 类似,也有两个并行任务 A 和 B。两个并行任务都完成后执行 action,action 依赖两个任务的结果,并对结果做转换,返回一个新值
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action)与runAfterBoth 类似,也有两个并行任务 A 和 B。两个并行任务任意一个完成后执行 action,action 中不关心任务的结果,action 也没有返回值
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)与runAfterBoth 类似,也有两个并行任务 A 和 B。两个并行任务任意一个完成后执行 action。如方法名和参数所示,action 是接受并消费两个任务结果的消费者,action 没有返回值
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)与runAfterBoth 类似,也有两个并行任务 A 和 B。两个并行任务任意一个完成后执行 action。action 将任务结果应用 action 的函数参数做转换,返回转换后的结果,类似于 stream 中的 map

4 多个任务执行编排

下面表格列出的每个方法都有对应两个版本的 async 方法,一个有executor 参数,一个没有。为了表格尽量简洁,表格中就不再列出async 方法了

方法说明
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)所有参数引用的任务都完成后,才触发执行当前的 CompletableFuture 实例任务。
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)参数引用的任务中任何一个完成后,就会触发执行当前的 CompletableFuture 实例任务。

5 CompletableFuture 其他方法

方法说明
public boolean cancel(boolean mayInterruptIfRunning)如果任务未完成,以 CancellationException 异常结束任务。
public boolean isCancelled()判断任务是否取消。
public T join()阻塞等待 获取返回值
public T get() throws InterruptedException, ExecutionException
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
阻塞等待(有超时重载版本)获取返回值。get 与 join区别,get 会抛出 checked 异常,调用代码需要处理异常。join 没有超时重载版本。
public T getNow(T valueIfAbsent)获取返回值,如果任务未完成则返回valueIfAbsent 参数指定value
public boolean isDone()任务是否执行完成

到此这篇关于Java中CompletableFuture 的详细介绍的文章就介绍到这了,更多相关CompletableFuture 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java中CompletableFuture 的详细介绍

本文链接: https://www.lsjlt.com/news/149402.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java中CompletableFuture 的详细介绍
    目录1.概述1.0 创建 CompletableFuture 的对象的工厂方法1.1 non-async 和 async 区别1.1.1 non-async 示例:注册 action...
    99+
    2022-11-13
  • Java NIO的详细介绍
    这篇文章主要讲解了“Java NIO的详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java NIO的详细介绍”吧!首先,我们需要弄清楚几个概念:同步和异步,阻塞和非阻塞。同步和异步...
    99+
    2023-06-16
  • 【JAVA IO 详细介绍】
    JAVA IO 详细介绍 目录一、什么是IO?1.1 IO的介绍1.2 流的介绍1.2.1 流的特征1.2.2 数据流的特征1.2.3 输入流的特征1.2.4 输出流的特征 二、...
    99+
    2023-10-26
    java
  • Java maven详细介绍
    目录maven什么是maven仓库的种类仓库的配置本地仓库配置私服配置中央仓库配置maven标准目录结构常用命令maven项目的生命周期pom.xml依赖适用域总结maven 什么是...
    99+
    2022-11-12
  • Java中IO流的详细介绍
    这篇文章主要介绍“Java中IO流的详细介绍”,在日常操作中,相信很多人在Java中IO流的详细介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中IO流的详细介绍”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-20
  • Java 方法(详细介绍)
    那么什么是方法呢?Java方法是语句的集合,它们在一起执行一个功能。 (推荐学习:java课程)方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点 使程序变得更...
    99+
    2017-06-19
    java教程 Java
  • java泛型详细介绍
    一. 泛型概念的提出(为什么需要泛型)?(推荐:java视频教程)首先,我们看下下面这段简短的代码:public class GenericTest { public static void main(String[] args)...
    99+
    2019-06-24
    java基础 java
  • Java中的各种锁详细介绍
    这篇文章主要讲解了“Java中的各种锁详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中的各种锁详细介绍”吧!锁有什么作用呢说了这么多还是不清楚锁到底有什么用处这一点就要深思我...
    99+
    2023-06-16
  • 详细介绍java中的byte类型
    Java也提供了一个byte数据类型,并且是基本类型。java byte是做为最小的数字来处理的,因此它的值域被定义为-128~127,也就是signed byte。下面这篇文章主要给大家介绍了关于java中byte类型的相关资料,需要的朋...
    99+
    2020-01-07
    java入门 java byte类型
  • 详细介绍Java中的各种锁
    一、一张图了解21种锁 二、乐观锁 应用 CAS 思想 一种乐观思想,假定当前环境是读多写少,遇到并发写的概率比较低,读数据时认为别的线程不会正在进行修改 实现 写数据...
    99+
    2022-11-12
  • Java中ArrayList的使用详细介绍
    目录1.ArrayList类1.1ArrayList类概述1.2ArrayList类常用方法1.2.1构造方法1.2.2成员方法1.2.3示例代码1.3ArrayList存储字符串并...
    99+
    2022-11-13
  • java中关于对象的详细介绍
    一、对象的创建步骤:(1)声名对象变量:对象变量的声明并没有创建对象,系统只是为该改变量分配一个引用空间。(2)对象的实例化:为对象分配空间,执行new运算符后的构造方法完成对象的初始化,并返回该对象的引用。过程:首先为对象分配内存空间,并...
    99+
    2014-08-23
    java入门 java 对象
  • java中关于scanner类的详细介绍
    1.Scanner的实现步骤第一步:在有效代码的第一行,通过import导入Scanner类!import java.util.Scanner;第二步:通过new关键字实例化一个Scanner对象!Scanner input = new S...
    99+
    2019-01-24
    java入门 java scanner
  • Java中的参数传递详细介绍
    目录前言1.值传递2.引用传递3.String类型传递4.举例总结前言 Java中的参数传递:分为值传递和引用传递但本质上,Java中只有值传递。引用传递,其实可以理解为传的是类似指...
    99+
    2022-11-12
  • 详细介绍java UDP通信
    介绍:UDP为用户数据报协议,在java中操纵UDP使用JDK中java.net包下的DatagramSocket和DatagramPacket类,可以方便的控制用户数据报文。DatagramPacket类将数据字节填充到UDP包中,这称为...
    99+
    2016-02-03
    java教程 java UDP通信
  • 浅析Java getResource详细介绍
    在 Java 中访问资源我们一般使用 getResource() 方法,亦或者直接new File()然后传入一个文件路径获取资源文件。但是这两者究竟有什么区别呢?由于平常在使用的时...
    99+
    2022-11-12
  • Java操作Redis详细介绍
    1. 简介Redis 是一个开源(BSD许可)的,内存中的key-value存储系统,它可以用作数据库、缓存和消息中间件。2. 对key的操作首先要建立连接Jedis jedis = new Jedis("127.0.0.1", 6379)...
    99+
    2023-05-30
    java redis使用
  • Java对象与Java类的详细介绍
    本篇内容介绍了“Java对象与Java类的详细介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录面向对象是什么Java类什么是类Java...
    99+
    2023-06-20
  • java的反射技术详细介绍
    本篇内容主要讲解“java的反射技术详细介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java的反射技术详细介绍”吧!反射的定义:审查元数据并收集关于它的类型信息的能力。下面介绍java的反...
    99+
    2023-06-17
  • 关于java泛型的详细介绍
    Java泛型泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 比如我们要写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,...
    99+
    2021-04-27
    java入门 java 泛型
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作