ForkJoinPool似乎浪费了一个线程

bma*_*ies 6 java fork-join java-7

我正在比较测试程序的两个变体.两者都ForkJoinPool在具有四个内核的机器上使用4线程运行.

在'模式1'中,我非常像执行器服务使用池.我把一堆任务扔进去ExecutorService.invokeAll.我获得了比普通的固定线程执行器服务更好的性能(即使有调用Lucene,那里也有一些I/O).

这里没有分而治之的.从字面上看,我做到了

ExecutorService es = new ForkJoinPool(4);
es.invokeAll(collection_of_Callables);
Run Code Online (Sandbox Code Playgroud)

在'模式2'中,我向池中提交单个任务,并在该任务中调用ForkJoinTask.invokeAll来提交子任务.所以,我有一个继承自的对象,RecursiveAction它被提交到池中.在该类的compute方法中,我调用了invokeAll来自不同类的对象集合,这些对象也继承自RecursiveAction.出于测试目的,我只提交第一个对象的一次一个.我天真地期望看到所有四个线程忙什么,因为线程调用invokeAll将为自己抓取一个子任务而不是仅仅坐着和阻塞.我可以想到为什么它可能不会那样工作的一些原因.

在VisualVM中观察,在模式2中,一个线程几乎总是在等待.我希望看到的是调用invokeAll的线程立即开始处理其中一个被调用的任务,而不仅仅是静坐.这肯定比使用普通线程池尝试此方案所导致的死锁更好,但仍然是什么?它是否保留一个线程,以防其他东西被提交?而且,如果是这样,为什么模式1中的问题不同?

到目前为止,我一直使用添加到java 1.6的引导类路径的jsr166 jar来运行它.

Vas*_*liy 3

ForkJoinTask.invokeAll 正在分叉所有任务,但列表中的第一个任务。它自行运行的第一个任务。然后它加入其他任务。它的线程不会以任何方式释放到池中。所以你所看到的,它是线程阻塞其他任务来完成的。