我怎么知道 Fork 和 Join 在 Java 中是否有足够的池大小?

How do I know if Fork and Join has enough pool size in Java?

我正在尝试对一些大数据实施分而治之的解决方案。我使用 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);
        ...
    }
}

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

每个 ForkJoinPool 都有一个已配置的目标 parallelism. This isn’t exactly matching the number of threads, i.e. if a worker thread is going to wait via a ManagedBlocker, the pool may start even more threads to compensate. The parallelism of the commonPool 默认为“CPU 核心数减一”,因此当将启动非池线程合并为助手时,由此产生的并行性将利用所有 CPU 个内核。

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

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

This value may be useful for heuristic decisions about whether to fork other tasks. In many usages of ForkJoinTasks, at steady state, each worker should aim to maintain a small constant surplus (for example, 3) of tasks, and to process computations locally if this threshold is exceeded.

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