Java并不使用所有可用的CPU

Java并不使用所有可用的CPU,java,multithreading,concurrency,java-8,fork-join,Java,Multithreading,Concurrency,Java 8,Fork Join,我有一个长时间运行的计算,我需要为一长串输入执行。这些计算是独立的,所以我想将它们分配到几个CPU。我正在使用Java8 代码的框架如下所示: ExecutorService executorService = Executors.newFixedThreadPool(numThreads); MyService myService = new MyService(executorService); List<MyResult> results = myI

我有一个长时间运行的计算,我需要为一长串输入执行。这些计算是独立的,所以我想将它们分配到几个CPU。我正在使用Java8

代码的框架如下所示:

ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

MyService myService = new MyService(executorService);

List<MyResult> results =
            myInputList.stream()
                     .map(myService::getResultFuture)
                     .map(CompletableFuture::join)
                     .collect(Collectors.toList());

executorService.shutdown();
CompletableFuture<MyResult> getResultFuture(MyInput input) {
    return CompletableFuture.supplyAsync(() -> longCalc(input), executor)))
}
所有计算线程都在等待相同的锁。在转储时,只有5个计算线程可运行,其余线程正在等待


锁定的原因可能是什么?为什么我无法使用所有CPU?

您正在提交作业并在稍后调用
join()
,等待异步作业完成

流中间步骤是按元素执行的,这意味着中间步骤
.map(CompletableFuture::join)
一次在一个元素上运行(更糟糕的是,它是一个连续的流),而不必确保所有元素都经过提交步骤。这会导致线程在等待每次计算完成时阻塞

在开始对作业调用
join()
之前,必须强制提交所有作业:

List<MyResult> results =
    myInputList.stream()
               .map(myService::getResultFuture)
               .collect(Collectors.toList()).stream()
               .map(CompletableFuture::join)
               .collect(Collectors.toList());

它仍然调用
join()
来检索结果,但此时,所有的未来都已完成,因此调用方不会被阻止。

CompletableFuture.SupplySync
会在作业返回之前将作业提交给执行者服务。如果这提高了并行性,您或OP是否可以解释造成差异的原因?@ErnestKiwele它确实提交给executor服务,但正如Holger所解释的,它会立即等待提交的单个任务完成。这与在单个线程上运行是一样的。Holger的修复程序首先将所有任务提交给executor服务,然后在提交所有任务后,等待返回的所有未来。谢谢,您完全正确,解决方案工作正常。我唯一的问题是,是什么解释了在修复之前通常仍使用了5-10个CPU?每次您向池提交作业时,任意工作线程都可能会拾取它,甚至线程到CPU的映射也没有修复(这是系统特定的)。因此,当您反复执行
submit
,然后立即执行
join
,您将为一个CPU核心生成100%的工作(加上一些开销),但它不必以一个核心的100%负载结束,但可能会分布在多个核心上,其负载低于100%。现在,CPU实际上并不是“80%忙”。它要么忙,要么空闲,因此监控工具必须记录一段时间内的状态以计算百分比。这使得快照不精确。
List<MyResult> results =
    myInputList.stream()
               .map(myService::getResultFuture)
               .collect(Collectors.toList()).stream()
               .map(CompletableFuture::join)
               .collect(Collectors.toList());
List<CompletableFuture<MyResult>> futures = myInputList.stream()
    .map(myService::getResultFuture)
    .collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(CompletableFuture<?>[]::new))
    .thenRun(() -> {
        List<MyResult> results = futures.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toList());
        // perform action with results
    });