The answer of Ivan Gammel 不准确。
确实没有与allOf() 返回的CompletableFuture 关联的执行程序,因为事实上,从来没有与任何CompletableFuture 关联的执行程序。
任务与执行器相关联,因为它在执行器内部运行,但关联是相反的:执行器有一个要执行的任务列表。
任务也可以与CompletableFuture 相关联,它会在任务完成时完成。 CompletableFuture 本身不保留对用于创建它的任务或执行程序的引用。然而,它可能会保留对任务的引用以及在相关阶段中使用的可选执行器。
allOf()返回的CompletableFuture会被一个task完成,这个task是原来CompletableFutures的一个依赖阶段。在您的示例中,此任务可以通过以下方式执行:
-
executor1,如果第三个任务先完成;
-
executor2,如果前两个任务在第三个任务之前完成;或
- 原始线程,如果所有任务在您调用
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
在主线程上完成(所有任务在allOf().thenRun()之前完成):
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
如何控制allOf()(或anyOf())之后使用的执行器
由于无法保证将使用的执行器,因此调用其中一种方法后应调用*Async(, executor) 来控制将使用哪个执行器。
如果您需要返回其中一个调用的结果 CompletableFuture,只需在返回之前添加 thenApplyAsync(i -> i, executor)。