例如-
CompletableFuture.supplyAsync(stage1).acceptEither(stage2, consumer );
stage1 和 stage2 应该在上面的代码中并行运行,因为它使用了
acceptEither
如果我更改为
acceptEitherAsync
,我发现我可以更好地控制哪个线程(来自 ForkJoin 池的线程或来自自定义执行程序池的线程)运行 stage2.
但是在运行下面的代码时(jdoddle 链接)我发现stage2
is not running in
main` 线程但是在 ForkJoin 池中。这怎么可能。
来自Java Doc -
为非异步方法的依赖完成提供的操作可能是 由完成当前 CompletableFuture 的线程执行, 或任何其他完成方法的调用者。
import java.util.concurrent.CompletableFuture;
public class MyClass {
public static void main(String args[]) {
System.out.println("hello world, CompletableFuturesRightHere");
CompletableFuture.supplyAsync(() -> {
System.out.println("log-sA: " + Thread.currentThread().getName());
System.out.println("log-sA post: " + Thread.currentThread().getName());
return 40;
}).acceptEither(CompletableFuture.supplyAsync(() -> {
System.out.println("log-aE: " + Thread.currentThread().getName());
System.out.println("log-aE post: " + Thread.currentThread().getName());
return 80;
}), a -> { System.out.println(a); } );
}
}
输出:
hello world, CompletableFuturesRightHere
log-aE: ForkJoinPool.commonPool-worker-5
log-sA: ForkJoinPool.commonPool-worker-3
log-aE post: ForkJoinPool.commonPool-worker-5
log-sA post: ForkJoinPool.commonPool-worker-3
40
stage2 即 log-aE 如何在 worker-5 中运行,它应该在 main 或 worker-3 中运行。但是由于 stage1 和 stage2 应该并行运行,而 worker-3 已经在运行 stage1,所以留给 stage2 的唯一线程是
main
。
stage2 怎么能在 worker-5 中运行。
如果您不在线执行所有操作,这可能会更清楚。例如:
// You used 'supplyAsync', which means the 'Supplier' will be executed
// using the common ForkJoinPool (any available thread from that pool)
CompletableFuture<Integer> stage1 = CompletableFuture.supplyAsync(() -> {
System.out.println("Stage 1: " + Thread.currentThread().getName());
return 40;
});
// You used 'supplyAsync' *again*, which means the 'Supplier' will be executed
// using the common ForkJoinPool (any available thread from that pool)
CompletableFuture<Integer> stage2 = CompletableFuture.supplyAsync(() -> {
System.out.println("Stage 2: " + Thread.currentThread().getName());
return 80;
});
/*
* Both 'stage1' and 'stage2' have been set to execute using the common
* ForkJoinPool. The use of 'acceptEither', or even 'acceptEitherAsync',
* has no bearing on that. Because you used 'acceptEither', the
* **CONSUMER** will be executed by the same thread which finished 'stage1'
* or the same thread that finished 'stage2', whichever happens first,
* or the caller thread (typically if 'stage1' and/or 'stage2' are already
* complete by the time 'acceptEither' is invoked).
*/
stage1.acceptEither(stage2, result -> {
System.out.println("Stage acceptEither: " + Thread.currentThread().getName());
System.out.println("Result = " + result);
});
注意:
supplyAsync
有一个重载接受一个Executor
,允许你指定一个不同于普通ForkJoinPool
的线程池。所有xxxAsync
方法也是如此。