CompletableFuture是Java 8中引入的一种实现异步编程模型的方式,它是Future的扩展,提供了更强大、更灵活的功能。CompletableFuture可以表示两个异步任务之间的顺序关系或并行关系,同时提供了一些方便的工具方法来组合这些关系。

CompletableFuture的一些特点和用法:

  1. 异步执行:CompletableFuture支持异步执行,可以使用supplyAsync()方法来创建一个异步执行的任务,并返回一个CompletableFuture对象。当任务结束后,可以使用get()方法获取返回值,该方法会阻塞等待任务执行结果。

  2. 异步结果处理:在CompletableFuture中,可以使用thenApply()、thenAccept()、thenRun()等方法来对异步操作的结果进行处理。这些方法使用函数式接口作为参数,可以将异步结果传递给下一个操作,并生成新的CompletableFuture对象。

  3. 组合操作:使用CompletableFuture可以方便地组合多个异步任务,以实现任务的顺序或并行关系。例如,可以使用thenCompose()方法将一个CompletableFuture对象与另一个异步任务组合成一个新的CompletableFuture对象,或使用thenCombine()方法将两个CompletableFuture对象的结果进行组合。

  4. 异常处理:CompletableFuture还提供了一些方法来处理异步任务中可能发生的异常,例如exceptionally()方法可以在异步任务出现异常时执行一些操作,然后返回一个新的CompletableFuture对象。

  5. 并行执行:CompletableFuture通过fork-join池实现了并行执行操作。可以使用parallel()方法将普通的Stream流转换为并行流来加速处理,也可以使用CompletableFuture自带的工具方法allOf()或anyOf()等方法一次性同时处理多个异步任务。

为什么要使用CompletableFuture

对于 CompletableFuture 这个类,它是 Java 并发编程中的重要组件之一,它能够帮助我们更加方便和灵活地处理异步任务,提高程序的执行效率和吞吐量。

        首先,CompletableFuture 是一种可以用于异步计算的 Future,它提供了丰富的方法来处理异步任务的结果。与传统的 Future 不同,CompletableFuture 可以通过回调函数或者连续的异步操作来处理任务结果,而无需在等待任务完成时一直阻塞线程。这使得我们可以更加灵活地编写并发代码,避免线程阻塞和死锁等问题。

        其次,CompletableFuture 支持串行和并行的异步计算,它的 API 设计非常易用,可以轻松地实现不同类型的异步任务的组合和流水线处理。例如,通过 thenCompose、thenCombine、thenApply 等操作方法,我们可以将多个 CompletableFuture 对象串接起来,形成操作链,从而实现对异步任务的精细控制和优化。

        此外,CompletableFuture 还支持异常处理、超时控制和响应式编程等特性。我们可以使用 exceptionally、handle、whenComplete、completeOnTimeout 等方法来捕获和处理异步任务的异常或者超时情况,从而保证程序的稳定性和可靠性。同时,通过 thenComposeAsync、thenApplyAsync 等异步方法,我们还可以实现响应式编程模型,从而更加高效地处理大量并发请求。

        总之,作为 Java 并发编程中的重要组件,CompletableFuture 非常适合处理异步任务,特别是在需要高吞吐量和高并发的场景下,它的灵活性和易用性使得我们可以轻松地实现复杂的异步计算和流水线处理,提高程序的性能和可维护性。因此,在进行 Java 开发时,可以优先考虑使用 CompletableFuture 来实现异步操作。

创建 CompletableFuture 对象的静态方法

CompletableFuture.supplyAsync

        根据指定的 Supplier 函数生成一个新的 CompletableFuture 对象,使用默认的 ForkJoinPool 执行异步任务。

        下面给出一个比较详细的 CompletableFuture.supplyAsync 方法使用示例,实现对两个字符串进行异步处理,并将它们合并起来:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    //模拟异步任务
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    //模拟异步任务
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "World";
});

CompletableFuture<String> result = future1.thenCombine(future2, (str1, str2) -> str1 + " " + str2);

//当异步任务完成后,获取结果并输出到控制台
result.thenAccept(System.out::println);

        在上面的代码中,我们定义了两个 CompletableFuture 对象,每个对象都包含一个 Supplier 函数,分别模拟了对字符串 "Hello" 和 "World" 的异步处理。然后,我们使用 thenCombine 方法把这两个 CompletableFuture 对象组合起来,定义一个 BiFunction 函数来处理两个 CompletableFuture 对象返回的结果,将它们合并成一个新的字符串。最后,我们通过调用 thenAccept 方法获取结果,并将结果输出到控制台。

        需要注意的是,在使用 CompletableFuture.supplyAsync 方法时,可以传入一个 Executor 对象来指定异步任务的线程池,如果不指定,则使用默认的 ForkJoinPool 线程池。此外,CompletableFuture 类还提供了一系列其他的方法,可以实现更加复杂的异步任务处理需求。

 CompletableFuture.runAsync

        根据指定的 Runnable 函数生成一个新的 CompletableFuture 对象,使用默认的 ForkJoinPool 执行异步任务。        

        下面给出一个使用自定义 ThreadPoolTaskExecutor 线程池的 CompletableFuture.runAsync 方法的示例,实现对一个任务进行异步处理,并在任务完成后输出一条日志:

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //定义线程池
executor.setCorePoolSize(5); //核心线程数
executor.setMaxPoolSize(10); //最大线程数
executor.setQueueCapacity(1000); //等待队列大小
executor.initialize(); //初始化线程池

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    //模拟异步任务
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Async task executed.");
}, executor); //指定线程池

future.thenRun(() -> System.out.println("Async task completed."));

//等待异步任务执行完毕
future.join();

//关闭线程池
executor.shutdown();

        在上面的代码中,我们创建了一个 ThreadPoolTaskExecutor 对象来定义一个具有 5 个核心线程、最大 10 个线程、等待队列大小为 1000 的线程池。然后,在调用 CompletableFuture.runAsync 方法时,我们传入该 ThreadPoolTaskExecutor 对象作为第二个参数,以便让 CompletableFuture 对象使用这个自定义的线程池来执行异步任务。

        最后,为了确保异步任务已经执行完毕,我们使用 join 方法等待 CompletableFuture 对象的执行结果。并在程序结束时关闭线程池,避免资源浪费。

        需要注意的是,在使用自定义 ThreadPoolTaskExecutor 线程池时,应根据实际场景选择不同的线程池类型和大小,以便更好地满足异步任务的执行需求,并避免因线程数量过多或线程阻塞导致性能下降。

合并多个 CompletableFuture 对象的组合方法

CompletableFuture.allOf

        根据多个 CompletableFuture 对象生成一个新的 CompletableFuture 对象,等待所有异步任务执行完毕后,把所有的异步任务结果封装到一个数组对象中并返回。

下面是一个使用 CompletableFuture.allOf 方法等待多个 CompletableFuture 对象执行完毕的示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "World";
});

CompletableFuture<Void> allFuture = CompletableFuture.allOf(future1, future2);

allFuture.join();

System.out.println("Future1 result: " + future1.get());
System.out.println("Future2 result: " + future2.get());

        在上面的代码中,我们创建了两个并发执行的 CompletableFuture 对象 future1 和 future2。其中,future1 的执行时间为 2 秒,而 future2 的执行时间为 1 秒。

        然后,我们调用 CompletableFuture.allOf 方法来等待所有 CompletableFuture 对象执行完毕。该方法接收一个 CompletableFuture 数组或可变参数列表作为参数,返回一个新的 CompletableFuture 对象,该对象在所有 CompletableFuture 对象执行完成后完成。在本例中,我们将 future1 和 future2 作为参数传递给 allOf 方法,以便在两个 CompletableFuture 对象均执行完毕后返回结果。

        接着,我们调用 join 方法等待原始 CompletableFuture 对象的结果,以确保它们都已经执行完毕。然后,我们通过调用 get 方法获取每个 CompletableFuture 对象的执行结果,并将结果打印到控制台。

        需要注意的是,与单个 CompletableFuture 对象不同的是,allOf 方法返回的 CompletableFuture 对象并不包含任何结果值。如果需要获取 CompletableFuture 数组中所有对象的执行结果,可以使用 CompletableFuture.join 方法,或者在 CompletableFuture 对象完成后调用 get 方法获取结果。另外,allOf 方法等待的所有 CompletableFuture 对象都必须已经完成,否则将会导致 allOf 方法一直阻塞。

CompletableFuture.anyOf

        根据多个 CompletableFuture 对象生成一个新的 CompletableFuture 对象,等待任意一个异步任务执行完毕后,返回该异步任务的结果。

下面是一个使用 CompletableFuture.anyOf 方法等待多个 CompletableFuture 对象中的任意一个执行完毕的示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "World";
});

CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);

anyFuture.thenAccept(result -> System.out.println("Result: " + result));

String joinResult = (String) anyFuture.join();
System.out.println("Join result: " + joinResult);

        在上面的代码中,我们同样创建了两个并发执行的 CompletableFuture 对象 future1 和 future2。其中,future1 的执行时间为 2 秒,而 future2 的执行时间为 1 秒。

        然后,我们调用 CompletableFuture.anyOf 方法来等待任意一个 CompletableFuture 对象执行完毕。该方法接收一个 CompletableFuture 数组或可变参数列表作为参数,返回一个新的 CompletableFuture 对象,该对象在任意一个 CompletableFuture 对象执行完成后完成。在本例中,我们将 future1 和 future2 作为参数传递给 anyOf 方法,以便在任意一个 CompletableFuture 对象执行完毕后返回结果。

        接着,我们通过调用 thenAccept 方法处理 CompletableFuture 对象的结果。在本例中,我们使用 Lambda 表达式来输出结果,即将返回的结果值打印到控制台。

        最后,我们调用 join 方法来等待 CompletableFuture 对象的执行结果,并将结果值打印到控制台。需要注意的是,由于 anyOf 方法只需要任意一个 CompletableFuture 对象执行完成即可返回结果,因此它的结果类型为 Object。如果需要将结果转换为特定类型,请确保使用强制类型转换或其他正确的转换方法。

        需要注意的是,如果希望等待多个 CompletableFuture 对象中的所有对象执行完毕,请使用 CompletableFuture.allOf 方法。如果希望等待多个 CompletableFuture 对象中的任意一个对象执行完毕,请使用 CompletableFuture.anyOf 方法。

CompletableFuture.thenApplyAsync 

    对当前 CompletableFuture 对象的结果进行转换,并返回一个新的 CompletableFuture 对象,使用默认的 ForkJoinPool 执行异步任务。

下面是一个使用 CompletableFuture.thenApplyAsync 方法对已有 CompletableFuture 对象的结果进行异步转换的示例:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

CompletableFuture<Integer> transformedFuture = future.thenApplyAsync(result -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return result.length();
});

System.out.println("Transformed future result: " + transformedFuture.join());

        在上面的代码中,我们首先创建了一个 CompletableFuture 对象 future,该对象会在后台线程中执行一个任务并返回结果 "Hello"。然后,我们调用 thenApplyAsync 方法对该 CompletableFuture 对象的结果进行转换。在本例中,我们将其转换为字符串长度,并在转换过程中模拟了 1 秒钟的延迟。

        需要注意的是,我们使用 thenApplyAsync 方法而不是 thenApply 方法。这是因为 thenApplyAsync 方法将结果转换到异步执行环境中,以便在后台线程中执行,从而避免阻塞主线程。如果使用 thenApply 方法,则转换结果将在当前线程中执行,从而可能导致主线程被阻塞。

        最后,我们通过调用 join 方法等待 CompletableFuture 对象执行完毕,并获取转换结果。在本例中,我们将转换结果打印到控制台中。

        需要注意的是,如果转换过程比较耗时,可以使用 thenApplyAsync 方法来将转换工作放到后台线程中执行,以便在后台线程中进行计算,并避免阻塞主线程。如果转换过程非常快,可以使用 thenApply 方法来在当前线程中执行转换操作,从而避免创建新的线程带来的额外开销。

thenCompose(Function<? super T,? extends CompletionStage<U>> fn) 

thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) 方法是 CompletableFuture 类中的一个组合方法,它用来将上一个 CompletableFuture 的结果转换为另一个 CompletableFuture,可以用来串联两个或多个异步任务。其方法签名如下:

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

其中,T 表示上一个 CompletableFuture 的结果类型,U 表示下一个 CompletableFuture 的结果类型。

使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + ", world!"));
String result = future2.get(); // 阻塞等待任务完成并获取结果
System.out.println(result); // 输出:Hello, world!

在上面的例子中,首先通过 supplyAsync 方法创建一个 CompletableFuture 对象 future1,该对象的结果是字符串 "Hello"。然后使用 thenCompose 方法将 future1 的结果作为参数传递给一个新的 CompletableFuture 对象 future2,这个新对象通过 supplyAsync 方法再次异步执行,将结果连接为 "Hello, world!"。

需要注意的是,在 thenCompose 方法中,传入的参数函数 fn 是一个接收类型为 T 的参数,并返回一个 CompletionStage<U> 对象的函数,其中 T 是上一个 CompletableFuture 的结果类型,U 是下一个 CompletableFuture 的结果类型。在这个函数中,你可以使用当前 CompletableFuture 的结果进行一些计算,然后返回一个新的 CompletableFuture 对象。在 thenCompose 方法中,会等待这个新对象执行完成,并以新对象的结果作为当前对象的结果。

如果需要多次进行 CompletableFuture 的串联,可以使用 thenCompose 方法多次调用。例如:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + ", world!"));
CompletableFuture<String> future3 = future2.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " I'm robot."));
String result = future3.get(); // 阻塞等待任务完成并获取结果
System.out.println(result); // 输出:Hello, world! I'm robot.

在这个示例中,我们基于上次转换的结果,完成了第三次 CompletableFuture 的串联操作。

需要注意的是,thenCompose 方法返回的 CompletableFuture 对象可能会因为出现异常而无法正常完成,此时可以通过 exceptionally 方法来处理异常。具体使用方法可以参考其他相关问题的回答。

CompletableFuture.thenComposeAsync 

        对当前 CompletableFuture 对象的结果进行转换,并返回一个新的 CompletableFuture 对象,使用默认的 ForkJoinPool 执行异步任务。与 thenApplyAsync 方法不同的是,thenComposeAsync 方法返回的 CompletableFuture 对象会合并两个异步任务的结果。

下面是一个使用 CompletableFuture.thenComposeAsync 方法对已有 CompletableFuture 对象的结果进行异步管道操作的示例:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

CompletableFuture<Integer> transformedFuture = future.thenComposeAsync(result -> {
    return CompletableFuture.supplyAsync(() -> result.length());
});

System.out.println("Transformed future result: " + transformedFuture.join());

    在上面的代码中,我们首先创建了一个 CompletableFuture 对象 future,该对象会在后台线程中执行一个任务并返回结果 "Hello"。然后,我们调用 thenComposeAsync 方法将其转换为另一个 CompletableFuture 对象 transformedFuture。在本例中,我们使用 thenComposeAsync 方法将前一个 CompletableFuture 对象的结果传递给一个新的 CompletableFuture 对象,并返回另一个 CompletableFuture 对象来处理新的结果。在这个示例中,我们使用了一个新的 CompletableFuture 对象来计算字符串长度,并将其作为处理管道的下一步。

    需要注意的是,我们使用 thenComposeAsync 方法而不是 thenCompose 方法。这是因为 thenComposeAsync 方法将结果转换到异步执行环境中,以便在后台线程中执行,从而避免阻塞主线程。如果使用 thenCompose 方法,则管道操作将在当前线程中执行,从而可能导致主线程被阻塞。

    最后,我们通过调用 join 方法等待 CompletableFuture 对象执行完毕,并获取转换结果。在本例中,我们将转换结果打印到控制台中。

    需要注意的是,thenComposeAsync 方法可以在原始 CompletableFuture 对象完成之后启动另一个 CompletableFuture 对象来同步处理结果,所以它非常适合那些需要对 CompletableFuture 的结果进行多步操作的场景。    

CompletableFuture.thenCombineAsync

    对当前 CompletableFuture 对象和另一个 CompletableFuture 对象的结果进行转换,并返回一个新的 CompletableFuture 对象,使用默认的 ForkJoinPool 执行异步任务。与 thenComposeAsync 方法不同的是,thenCombineAsync 方法返回的 CompletableFuture 对象只包含两个异步任务的结果中的一个。

下面是一个使用 CompletableFuture.thenCombineAsync 方法对两个 CompletableFuture 对象进行异步组合操作的示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");

CompletableFuture<String> combinedFuture = future1.thenCombineAsync(future2, (result1, result2) -> {
    return result1 + " " + result2;
});

System.out.println("Combined future result: " + combinedFuture.join());

    在上面的代码中,我们首先创建了两个 CompletableFuture 对象:future1 和 future2,它们都会在后台线程中执行一个任务并返回结果 "Hello" 和 "World"。然后,我们调用 thenCombineAsync 方法将这两个 CompletableFuture 对象组合起来,并在组合时指定一个 BiFunction,将它们的结果拼接成一个字符串,并返回一个新的 CompletableFuture 对象。

    需要注意的是,我们使用 thenCombineAsync 方法而不是 thenCombine 方法。这是因为 thenCombineAsync 方法将结果转换到异步执行环境中,以便在后台线程中执行,从而避免阻塞主线程。如果使用 thenCombine 方法,则组合操作将在当前线程中执行,从而可能导致主线程被阻塞。

    最后,我们通过调用 join 方法等待 CompletableFuture 对象执行完毕,并获取组合结果。在本例中,我们将组合结果打印到控制台中。

    需要注意的是,thenCombineAsync 方法可以用于将多个 CompletableFuture 对象组合起来进行处理。它非常适合那些需要对多个 CompletableFuture 的结果进行组合处理的场景。

thenAcceptBoth

thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)CompletableFuture 类的一个组合方法。它能够将两个 CompletableFuture 的结果合并,然后执行特定的操作(使用传入的 BiConsumer 对象对合并结果进行处理),并返回一个新的 CompletableFuture<Void> 对象(因为该方法没有返回值)。其方法签名如下:

public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);

其中,T 表示当前 CompletableFuture 的结果类型,U 表示其他 CompletableFuture 的结果类型。

使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 123);

CompletableFuture<Void> future3 = future1.thenAcceptBoth(future2, (s, i) -> {
    System.out.println(s + " " + i); // 输出:Hello 123
});

future3.get(); // 阻塞等待任务完成

在上面的示例中,通过 supplyAsync 方法创建了两个 CompletableFuture 对象 future1future2,分别表示字符串 "Hello" 和整数 123。然后通过 thenAcceptBoth 方法将这两个 CompletableFuture 的结果合并,并在合并结果上执行一个特定的操作(这里是打印合并结果的语句)。

需要注意的是,thenAcceptBoth 方法返回的 CompletableFuture 对象没有结果值,只用于表示操作的完成状态。如果需要获取合并操作的结果值,可以通过前面讲解过的 thenApplythenCombine 等方法来实现。

另外,如果需要在两个 CompletableFuture 对象都完成后执行特定的操作(无需合并结果),可以使用 runAfterBoth 方法。如果只需要在当前 CompletableFuture 和其中一个其他 CompletableFuture 完成之后执行特定的操作,可以使用 runAfterEitheracceptEither 等方法。这些方法的作用和语法略有不同,可以根据具体需求进行选择。

thenAcceptBothAsync

thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor)CompletableFuture 类的一个异步组合方法。它和 thenAcceptBoth 方法的作用相同,都是将两个 CompletableFuture 的结果合并,然后执行特定的操作,并返回一个新的 CompletableFuture<Void> 对象(因为该方法没有返回值)。不同的是,这个方法会使用指定的线程池来执行操作,可以使操作在另外一个线程上异步执行,避免当前线程阻塞等待操作完成。其方法签名如下:

public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor);

其中,T 表示当前 CompletableFuture 的结果类型,U 表示其他 CompletableFuture 的结果类型。

使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 123);

CompletableFuture<Void> future3 = future1.thenAcceptBothAsync(future2, (s, i) -> {
    System.out.println(s + " " + i); // 输出:Hello 123
}, Executors.newFixedThreadPool(1));

future3.get(); // 阻塞等待任务完成

在上面的示例中,通过 supplyAsync 方法创建了两个 CompletableFuture 对象 future1future2,分别表示字符串 "Hello" 和整数 123。然后通过 thenAcceptBothAsync 方法将这两个 CompletableFuture 的结果合并,并在指定的线程池上执行一个特定的操作(这里是打印合并结果的语句)。

需要注意的是,thenAcceptBothAsync 方法返回的 CompletableFuture 对象没有结果值,只用于表示操作的完成状态。如果需要获取合并操作的结果值,可以通过前面讲解过的 thenApplyAsyncthenCombineAsync 等方法来实现。

另外,如果需要在两个 CompletableFuture 对象都完成后异步执行特定的操作(无需合并结果),可以使用 runAfterBothAsync 方法。如果只需要在当前 CompletableFuture 和其中一个其他 CompletableFuture 完成之后异步执行特定的操作,可以使用 runAfterEitherAsyncacceptEitherAsync 等方法。这些方法的作用和语法略有不同,可以根据具体需求进行选择。

runAfterBoth 

runAfterBoth(CompletionStage<?> other, Runnable action)CompletableFuture 类的一个组合方法。它能够在当前 CompletableFuture 和另一个 CompletableFuture 都完成后执行一个特定的操作,无需合并结果,并返回一个新的 CompletableFuture<Void> 对象(因为该方法没有返回值)。其方法签名如下:

public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action);

 其中,other 表示另外一个 CompletableFuture 对象,它的结果类型不确定,用通配符 ? 表示;action 表示特定的操作,它是一个 Runnable 对象,没有参数和返回值。

使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 123);

CompletableFuture<Void> future3 = future1.runAfterBoth(future2, () -> {
    System.out.println("Both completed.");
});

future3.get(); // 阻塞等待任务完成

在上面的示例中,通过 supplyAsync 方法创建了两个 CompletableFuture 对象 future1future2,分别表示字符串 "Hello" 和整数 123。然后通过 runAfterBoth 方法在这两个 CompletableFuture 都完成后执行一个特定的操作(这里是打印提示信息的语句)。

需要注意的是,runAfterBoth 方法返回的 CompletableFuture 对象没有结果值,只用于表示操作的完成状态。如果需要获取合并操作的结果值,可以通过前面讲解过的 thenApplythenCombine 等方法来实现。

另外,如果需要在当前 CompletableFuture 和其中一个其他 CompletableFuture 完成之后执行特定的操作,可以使用 runAfterEitheracceptEither 等方法。如果需要在两个 CompletableFuture 对象都完成后异步执行特定的操作,可以使用 runAfterBothAsync 方法。这些方法的作用和语法略有不同,可以根据具体需求进行选择。

runAfterBothAsync

runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor)CompletableFuture 类的一个异步组合方法。它和 runAfterBoth 方法的作用相同,都是在当前 CompletableFuture 和另一个 CompletableFuture 都完成后执行一个特定的操作,无需合并结果,并返回一个新的 CompletableFuture<Void> 对象(因为该方法没有返回值)。不同的是,这个方法会使用指定的线程池来执行操作,可以使操作在另外一个线程上异步执行,避免当前线程阻塞等待操作完成。其方法签名如下:

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor);

其中,other 表示另外一个 CompletableFuture 对象,它的结果类型不确定,用通配符 ? 表示;action 表示特定的操作,它是一个 Runnable 对象,没有参数和返回值;executor 表示执行操作的线程池。

使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 123);

CompletableFuture<Void> future3 = future1.runAfterBothAsync(future2, () -> {
    System.out.println("Both completed.");
}, Executors.newFixedThreadPool(1));

future3.get(); // 阻塞等待任务完成

在上面的示例中,通过 supplyAsync 方法创建了两个 CompletableFuture 对象 future1future2,分别表示字符串 "Hello" 和整数 123。然后通过 runAfterBothAsync 方法在这两个 CompletableFuture 都完成后执行一个特定的操作(这里是打印提示信息的语句),并使用指定的线程池来执行操作。

需要注意的是,runAfterBothAsync 方法返回的 CompletableFuture 对象没有结果值,只用于表示操作的完成状态。如果需要获取合并操作的结果值,可以通过前面讲解过的 thenApplyAsyncthenCombineAsync 等方法来实现。

另外,如果需要在当前 CompletableFuture 和其中一个其他 CompletableFuture 完成之后异步执行特定的操作(无需合并结果),可以使用 runAfterEitherAsync 方法。如果需要在两个 CompletableFuture 对象都完成后异步执行特定的操作(需要合并结果),可以使用 thenAcceptBothAsyncthenCombineAsync 等方法。这些方法的作用和语法略有不同,可以根据具体需求进行选择。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐