我如何知道 Java 中的 Fork 和 Join 是否有足够的池大小?

Wil*_*hou 4 java multithreading fork-join forkjoinpool

我正在尝试对一些大数据实施分而治之的解决方案。我使用 fork 和 join 将事物分解为线程。但是我有一个关于分叉机制的问题:如果我将分而治之的条件设置为:

@Override
protected SomeClass compute(){
    if (list.size()<LIMIT){
        //Do something here
        ...
    }else{
        //Divide the list and invoke sub-threads
        SomeRecursiveTaskClass subWorker1 = new SomeRecursiveTaskClass(list.subList());
        SomeRecursiveTaskClass subWorker2 = new SomeRecursiveTaskClass(list.subList());
        invokeAll(subWorker1, subWorker2);
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果没有足够的资源可供调用subWorker(例如池中没有足够的线程),会发生什么情况?Fork/Join 框架是否维护可用线程的池大小?或者我应该将这个条件添加到我的分治逻辑中?

Hol*_*ger 7

每个ForkJoinPool都有一个配置的目标并行度。这与 xe2x80x99t 与线程数完全匹配,即如果工作线程要通过 a 等待ManagedBlocker,池可能会启动更多线程来补偿。默认的并行度commonPool为 \xe2\x80\x9c CPU 核心数减去 1\xe2\x80\x9d,因此当将启动非池线程合并为辅助线程时,生成的并行度将利用所有 CPU 核心。

\n\n

当您提交的作业多于线程时,它们将被排队。将一些作业排队可以帮助利用线程,因为并非所有作业都可以完全相同的时间运行,因此运行完工作的线程可能会窃取其他线程的作业,但过多地分割工作可能会产生不必要的开销。

\n\n

因此,您可以用来ForkJoinTask.getSurplusQueuedTaskCount()获取当前挂起的作业数量,这些作业不太可能被其他线程窃取,并且仅当它低于一个小阈值时才进行拆分。正如其文档所述:

\n\n
\n

该值对于是否分叉其他任务的启发式决策可能有用。在 ForkJoinTasks 的许多用法中,在稳定状态下,每个工作线程的目标应该是维持少量恒定的任务剩余(例如 3 个),并在超过此阈值时在本地处理计算。

\n
\n\n

所以这是决定是否进一步分工的条件。由于这个数字反映了空闲线程何时窃取您创建的作业,因此当作业具有不同的 CPU 负载时​​,它将导致平衡。另外,它的工作方式相反,如果池是共享的(如公共池)并且线程已经很忙,它们将不会接手您的作业,剩余计数将保持较高水平,然后您将自动停止拆分。

\n