Java8 ForkJoinPool和Executors.newWorkStealingPool之间的详细区别?

时间:2016-12-27 00:02:45

标签: multithreading executorservice fork-join executors forkjoinpool

使用中的低级差异是什么:

.styl

ForkJoinPool = new ForkJoinPool(X);

X 是所需的并行级别,即线程运行..

根据文档我发现它们相似。还告诉我哪一个在任何正常用途下更合适和安全。 我有 130 百万个条目写入BufferedWriter并使用Unix排序按第1列排序。

另请告诉我有多少线程可以保留。

注意: 我的系统有 8 核心处理器和 32 GB RAM。

3 个答案:

答案 0 :(得分:19)

工作窃取是现代线程池使用的一种技术,用于减少对工作队列的争用。

经典线程池有一个队列,每个线程池线程锁定队列,使任务出列,然后解锁队列。如果任务很短并且有很多任务,那么队列上存在很多争用。使用无锁队列确实有帮助,但并不能完全解决问题。

现代线程池使用工作窃取 - 每个线程都有自己的队列。当线程池线程产生一个任务时 - 它将它排入自己的队列。当线程池线程想要使任务出列时 - 它首先尝试将任务从他自己的队列中出列,如果它没有任何 - 它从其他线程队列中“窃取”工作。这确实减少了theradpool的争用并提高了性能。

newWorkStealingPool创建一个利用工作用途的线程池,其线程数为处理器数。

newWorkStealingPool提出了一个新问题。如果我有四个逻辑核心,那么池总共有四个线程。如果我的任务阻止 - 例如在同步IO上 - 我没有充分利用我的CPU。我想要的是在任何给定时刻的四个活动线程,例如 - 加密AES的四个线程和等待IO完成的另外140个线程。

这是ForkJoinPool提供的 - 如果您的任务产生新任务并且该任务等待它们完成 - 池将注入新的活动线程以使CPU饱和。值得一提的是ForkJoinPool也利用了工作窃取。

使用哪一个?如果您使用fork-join模型或者您知道任务无限期阻塞,请使用ForkJoinPool。如果您的任务很短且主要受CPU限制,请使用newWorkStealingPool

并且在说完之后,现代应用程序倾向于使用具有可用处理器数量的线程池并利用异步IO 无锁容器以便防止阻塞。这(通常)给出了最好的表现。

答案 1 :(得分:1)

newWorkStealingPoolForkJoinPool的更高抽象级别。

如果您查看Oracle jvm实现,它只是一个预先配置的ForkJoinPool public static ExecutorService newWorkStealingPool() { return new ForkJoinPool (Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); } 不幸的是,查看实现并不是理解课程目的的正确方法。 同样归功于:https://dzone.com/articles/diving-into-java-8s-newworkstealingpools

答案 2 :(得分:1)

这只是Fork / Join Framework的抽象...

/**
* Creates a work-stealing thread pool using all
* {@link Runtime#availableProcessors available processors}
* as its target parallelism level.
* @return the newly created thread pool
* @see #newWorkStealingPool(int)
* @since 1.8
*/
public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
                            ForkJoinPool.defaultForkJoinWorkerThreadFactory,
                            null, true);
}