我的电脑是四核(FYI)
CompletableFuture将使用ForkJoinPool.commonPool()
作为其official doc指出:
使用ForkJoinPool.commonPool()执行所有没有显式Executor参数的异步方法(除非它不支持至少两个的并行级别,在这种情况下,创建一个新的Thread来运行每个任务)。 / p>
我调试了CompletableFuture.supplyAsync(Supplier<U> supplier)
private static final boolean useCommonPool =
(ForkJoinPool.getCommonPoolParallelism() > 1);
/**
* Default executor -- ForkJoinPool.commonPool() unless it cannot
* support parallelism.
*/
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
这意味着parallelStream
始终使用ForkJoinPool.commonPool()
,但这里为什么它更快。
我尝试将它们打印出来,并在使用CompletableFuture时发现只有三个线程:
private static int concurrencyGet() {
List<CompletableFuture<Integer>> futureList = IntStream.rangeClosed(0, 10).boxed()
.map(i -> CompletableFuture.supplyAsync(() -> getNumber(i)))
.collect(Collectors.toList());
return futureList.stream().map(future -> future.join()).reduce(0, Integer::sum);
}
但parallelStream使用四,包括主线程。
我的猜测是,在CompletableFuture.supplyAsync()
中,ForkJoinPool.getCommonPoolParallelism()
仅三,而主要线程占据四个中的一个,因为它是异步。
但 parallelStream 将耗尽所有四,因为它不是异步。
这是对的吗?我想知道这个问题是否有一些官方文件?
感谢您的帮助。
答案 0 :(得分:0)
以下是我对 Venkat Subramaniam 关于Parallel and Asynchronous Programming with Streams and CompletableFuture的讨论的理解:
由于CompleteableFuture
也使用ForkJoinPool.commonPool()
,它也可以使用主线程,并且在某些情况下也可以。
给出以下示例
public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> numberSupplier());
future.thenAccept(i -> System.out.println("f: " + i + " - " + Thread.currentThread()));
sleep(100); //wait for async operations to finish before exiting
}
private static Integer numberSupplier() {
Integer n = 2;
System.out.println("c: " + n + " - " + Thread.currentThread());
sleep(19);
return n;
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
你可能得到这样的控制台输出:
c: 2 - Thread[ForkJoinPool.commonPool-worker-1,5,main]
f: 2 - Thread[ForkJoinPool.commonPool-worker-1,5,main]
supplyAsync(..)
以及thenAccept(..)
部分都由ForkJoinPool
的工作线程执行。
但是,如果给Supplier<Integer>
的{{1}}如此之快,那么在调用supplyAsync(..)
时它就完成了,那么第二部分也可能在主线程中执行:
thenAccept(..)
输出:
private static Integer numberSupplier() {
Integer n = 2;
//System.out.println("c: " + n + " - " + Thread.currentThread());
//sleep(19);
return n;
}