当前位置: 首页 > 知识库问答 >
问题:

CompletableFuture.all使用哪个执行程序?

陈实
2023-03-14

假设我们有两个执行人,1和2。

我们可以配置在执行时使用哪个执行器

CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(()-> {return 1;}, executor1) //executor1
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(()-> {return 2;}, executor1) //executor1
CompletableFuture<Integer> cf3 = CompletableFuture.supplyAsync(()-> {return 3;}, executor2) //executor2

但哪个线程执行器使用CompletableFuture静态方法allOf?

CompletableFuture.allOf(cf1, cf2, cf3)

谢啦!

共有2个答案

应志用
2023-03-14

没有与CompletableFuture#allOf相关联的执行器,它只会生成CompletableFuture,它将在同一个线程中等待依赖项的完成,您将在该线程中调用CompletableFuture#get()。

在您的示例中,cf1和cf2后面的任务仍将由执行器1执行,cf2中的任务将由执行器2执行,这是allOf(…)的结果。get()将在当前线程中返回,并且不会在后台启动其他线程。

下面是一个示例,您可以通过在System.out.println行上设置断点并检查活动线程列表来观察IDE中的实际行为。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

import static java.util.concurrent.CompletableFuture.supplyAsync;

public class ExecutorTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Executor executor1 = Executors.newSingleThreadExecutor();
        Executor executor2 = Executors.newSingleThreadExecutor();
        CompletableFuture<Integer> cf1 = supplyAsync(run(1), executor1); //executor1
        CompletableFuture<Integer> cf2 = supplyAsync(run(2), executor1); //executor1
        CompletableFuture<Integer> cf3 = supplyAsync(run(3), executor2); //executor2
        CompletableFuture<Void> result = CompletableFuture.allOf(cf1, cf2, cf3);
        new Thread(() -> {
            try {
                result.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("Waiting now...");
    }

    private static Supplier<Integer> run(int result) {
        return () -> runDelayed(result);
    }

    private static int runDelayed(int result) {
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

}
廉飞捷
2023-03-14

伊凡·加梅尔的答案并不准确。

实际上,没有与allOf()返回的CompletableFuture相关联的执行器,因为事实上,从来没有与任何CompletableFuture相关联的执行器。

任务与执行程序相关联,因为它在其中运行,但关联是反向的:执行程序有一个要执行的任务列表。

任务还可以与可完成的未来相关联,该未来将在任务完成时完成。CompletableFuture本身不保留对用于创建它的任务或执行器的引用。然而,它可以保留对任务的引用,并可以选择在依赖阶段中使用的执行器。

由allOf()返回的CompletableFuture将由任务完成,该任务是原始CompletableFuture的从属阶段。在您的示例中,此任务可以通过以下方式执行:

  • 如果第三个任务首先完成,则执行者1
  • 如果前两个任务在第三个任务之前完成,则执行器2;或
  • 如果在调用allOf()之前所有任务都已完成,则为原始线程

这可以通过向allOf()调用添加依赖的thenRun()阶段来看出:

public class CompletableFutureAllOfCompletion {
    private ExecutorService executor1 = Executors.newFixedThreadPool(2);
    private ExecutorService executor2 = Executors.newFixedThreadPool(2);
    private Random random = new Random();

    public static void main(String[] args) {
        new CompletableFutureAllOfCompletion().run();
    }

    public void run() {
        CompletableFuture<Integer> cf1 = supplyAsync(this::randomSleepAndReturn, executor1);
        CompletableFuture<Integer> cf2 = supplyAsync(this::randomSleepAndReturn, executor1);
        CompletableFuture<Integer> cf3 = supplyAsync(this::randomSleepAndReturn, executor2);
        randomSleepAndReturn();
        CompletableFuture.allOf(cf1, cf2, cf3)
                .thenRun(() -> System.out.println("allOf() commpleted on "
                        + Thread.currentThread().getName()));

        executor1.shutdown();
        executor2.shutdown();
    }

    public int randomSleepAndReturn() {
        try {
            final long millis = random.nextInt(1000);
            System.out.println(
                    Thread.currentThread().getName() + " waiting for " + millis);
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }
}
pool-1-thread-1 waiting for 937
pool-1-thread-2 waiting for 631
main waiting for 776
pool-2-thread-1 waiting for 615
allOf() commpleted on pool-1-thread-1
pool-1-thread-1 waiting for 308
pool-1-thread-2 waiting for 788
main waiting for 389
pool-2-thread-1 waiting for 863
allOf() commpleted on pool-2-thread-1
pool-1-thread-1 waiting for 168
pool-1-thread-2 waiting for 292
main waiting for 941
pool-2-thread-1 waiting for 188
allOf() commpleted on main

由于无法保证将使用的执行器,因此对其中一个方法的调用之后应该是异步(,executor)调用,以控制将使用哪个执行器。

如果需要返回其中一个调用的结果CompletableFuture,只需添加一个applyasync(i-

 类似资料:
  • 我在某个存储库类上有一个方法,它返回。完成这些期货的代码使用一个第三方库来阻止。我打算有一个单独的有界,这个存储库类将使用它来进行这些阻塞调用。 这里有一个例子: 我的应用程序的其余部分将组成这些期货,并用结果做一些其他的事情。当提供给、、等的其他函数时,我不希望它们在存储库的上运行。 另一个例子: JavaDoc声明: 为非异步方法的从属完成提供的操作可以由完成当前CompletableFutu

  • 在阅读关于流的留档时,我遇到了以下句子: > 。。。试图从行为参数访问可变状态会给您带来错误的选择。。。如果您不同步对该状态的访问,您将面临数据竞争,因此您的代码将被破坏。。。[1] 如果行为参数确实有副作用。。。[没有]保证在同一个线程中执行同一流管道中“相同”元素上的不同操作。[2] 对于任何给定的元素,可以在库选择的任何时间和线程中执行该操作。[3] 这些句子没有区分顺序流和平行流。因此,我

  • 问题内容: 我对CompletableFuture方法有疑问: 事情是JavaDoc这么说的: 返回一个新的CompletionStage,当此阶段正常完成时,将使用该阶段的结果作为所提供函数的参数来执行该阶段。有关涵盖异常完成的规则​​,请参见CompletionStage文档。 那线程呢?这将在哪个线程中执行?如果将来由线程池完成怎么办? 问题答案: 文档中指定的策略可以帮助您更好地理解: 对

  • 我有一个关于CompletableFuture方法的问题: 问题是JavaDoc只说了这么一句话: 返回一个新的CompletionStage,当此阶段正常完成时,将以此阶段的结果作为所提供函数的参数执行该CompletionStage。有关例外完成的规则,请参阅CompletionStage文档。 穿线呢?这将在哪个线程中执行?如果未来是由一个线程池来完成的呢?

  • 我需要执行一些任务。有些任务是独立的,有些任务依赖于其他任务的成功执行。独立任务可以并行运行以获得更好的性能。我把这些任务称为服务。列说明哪些服务将以串联方式执行,哪些服务将以并联方式执行。列描述了一组定义的服务所遵循的执行顺序。例如,服务A和B应该并行运行。如果它们已成功执行,则将执行服务C。请注意,服务C并不直接依赖于其先前服务的输出,但它必须在成功执行其先前服务后运行,因为服务C在执行期间需

  • 问题内容: 我的项目有多个使用方法的类。如何告诉Spring Boot Maven插件应将其用作主类? 问题答案: 在pom中添加您的入门班: 要么