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

时间:2018-04-21 20:15:05

标签: java parallel-processing java-8 completable-future

假设我们有两个执行器,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 个答案:

答案 0 :(得分:4)

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

在您的示例中,cf1cf2后面的任务仍将由executor1执行,cf2中的任务将由executor2执行, 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;
    }

}

答案 1 :(得分:4)

The answer of Ivan Gammel并不确切。

确实没有与CompletableFuture返回的allOf()相关联的执行程序,事实上,没有任何执行程序与任何CompletableFuture相关联。

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

任务也可以与CompletableFuture相关联,它将在任务完成时完成。 CompletableFuture本身不会保留对用于创建它的任务或执行程序的引用。但是,它可以保留对依赖阶段中使用的任务和可选执行器的引用。

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

  • executor1,如果第三个任务先完成;
  • executor2,如果第一个任务在第三个任务之前完成;或
  • 原始主题,如果在调用allOf()之前完成所有任务。

通过在thenRun()电话中添加一个从属allOf()阶段可以看出这一点:

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