我正在比较一个测试程序的两个变体。两者都ForkJoinPool
在具有四个内核的机器上使用 4 线程运行。
在“模式 1”中,我非常像使用执行器服务一样使用池。我把一堆任务扔进ExecutorService.invokeAll
. 与普通的固定线程执行器服务相比,我获得了更好的性能(即使有对 Lucene 的调用,在那里执行一些 I/O)。
这里没有分而治之。从字面上看,我愿意
ExecutorService es = new ForkJoinPool(4);
es.invokeAll(collection_of_Callables);
在“模式 2”中,我将单个任务提交到池中,并在该任务中调用 ForkJoinTask.invokeAll 来提交子任务。所以,我有一个继承自 的对象,RecursiveAction
它被提交到池中。在该类的计算方法中,我调用了来自另一个invokeAll
类的对象集合,该类也继承自. 出于测试目的,我一次只提交一个第一个对象。我天真地期望看到所有四个线程都忙的事情,因为线程调用会为自己抓取其中一个子任务,而不是仅仅坐着阻塞。我能想到一些为什么它可能无法以这种方式工作的原因。RecursiveAction
invokeAll
在 VisualVM 中观察,在模式 2 中,一个线程几乎总是在等待。我期望看到的是调用invokeAll 的线程会立即处理其中一个被调用的任务,而不是静止不动。这肯定比使用普通线程池尝试这种方案所导致的死锁要好,但是,怎么办?如果提交其他内容,它是否会阻止一个线程?如果是这样,为什么模式 1 中没有同样的问题?
到目前为止,我一直在使用添加到 java 1.6 的引导类路径中的 jsr166 jar 来运行它。