【问题标题】:Detailed difference between Java8 ForkJoinPool and Executors.newWorkStealingPool?Java8 ForkJoinPool 和 Executors.newWorkStealingPool 的详细区别?
【发布时间】:2016-12-27 00:02:45
【问题描述】:

使用之间的低级区别是什么:

ForkJoinPool = new ForkJoinPool(X);

ExecutorService ex = Executors.neWorkStealingPool(X);

其中 X 是所需的并行级别,即正在运行的线程..

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

如果可能,请告诉我要保留多少线程。

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

【问题讨论】:

  • 我在等待更多答案。

标签: multithreading executorservice fork-join executors forkjoinpool


【解决方案1】:

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

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

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

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

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

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

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

话虽如此,现代应用程序倾向于使用具有可用处理器数量的线程池,并利用 asynchronous IOlock-free-containers 以防止阻塞。这(通常)提供最佳性能。

【讨论】:

  • 为了让 F/J 池为阻塞线程创建一个新的工作线程,请使用 ForkJoinPool.ManagedBlocker。但是你最终可能会得到 140 个新线程,因为这 140 个线程在 I/O 上阻塞。
  • David Haim,所以 ForkJoinPool 不仅可以从其他线程的队列中窃取工作,还可以在必要时产生新的线程,这有什么区别?但是(如果是的话)和 newcachedthreadpool 有什么区别?
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这只是 Fork/Join 框架的抽象...

    /**
    * 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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 2011-11-28
      • 2018-12-29
      • 1970-01-01
      相关资源
      最近更新 更多