【问题标题】:Why does ForkJoinPool.commonPool().execute(runnable) take more time to run the thread为什么 ForkJoinPool.commonPool().execute(runnable) 需要更多时间来运行线程
【发布时间】:2018-08-03 07:00:19
【问题描述】:

我使用ForkJoinPool.commonPool().execute(runnable) 作为在我的应用程序的许多地方生成线程的便捷方式。但是在特定的调用中,调用线程中可运行的代码需要更多时间(超过 10 秒)。这可能是什么原因?如何避免?

编辑:根据@ben 的回答,避免线程池中长时间运行的进程似乎是解决方案。手动创建新线程解决了我的问题,而不是使用常见的 ForkJoinPool。

【问题讨论】:

  • 你是不是很多地方都在使用公用池?默认情况下,它的线程数与内核数一样多,因此很容易填充。
  • 您的池可能同时充满了太多任务。除此之外,我不完全确定为什么它会比生成线程慢,因为在内部它只是一个静态构造的线程池,不应该更慢(也不会慢 10 秒)
  • @ben 我碰巧延迟了将近 10 秒。
  • @kayaman 是的。我认为使用公共池将是一种有效的方式,因为它知道如何使用核心并将利用它。
  • @Loganathan 不要使用@anyone,因为它的工作方式与@noone 一样,即没有人收到通知。当您不需要线程池功能并且任务需要一秒钟或更长时间时,只需生成一个新线程,因为没有任何收获。线程池让您可以控制正在运行的任务数量,并且每个任务的开销要小得多(我猜,创建线程需要花费很多微秒)。

标签: java multithreading performance threadpool forkjoinpool


【解决方案1】:

所以经过一些快速测试后,我发现了问题。看下面的示例代码:

List<Runnable> runnables = new ArrayList<Runnable>();
for (int i = 0; i < 20; ++i)
{
    runnables.add(() -> {
        System.out.println("Runnable start");
        try
        {
            Thread.sleep(10000);
        }
        catch (InterruptedException e)
        {

        }
        System.out.println("Runnable end");
    });
}

for (Runnable run : runnables)
{
    //ForkJoinPool.commonPool().execute(run);
    //new Thread(run).start();
}

在两行之一中进行注释。 我们创建了许多发送消息的可运行程序,闲置 10 秒,然后再次发送消息。很简单。

当使用线程时,所有 Runnable 发送 Runnable start 10s pass,所有 runnable 发送 Runnable end

当使用 commonPool() 时,只有一部分发送 Runnable start 10s pass,他们发送 Runnable end 并且另一组发送 Runnable start 直到全部完成。

这仅仅是因为系统上的内核数量决定了线程池将容纳多少线程。当所有线程都被填满时,直到一个线程被释放后才会执行新任务。

故事的寓意是:仅当您知道线程池的内部工作方式并且这就是您希望它做的事情时才使用它。

【讨论】:

  • 不,故事的寓意是不要使用 commonPool,除非您了解它的工作原理。创建你自己的执行器,并在其中放入你想要的线程数。
  • 嗯,这是一种更好的表达方式。我会编辑。
  • @both_of_you 在我的应用程序的许多地方生成单个线程以在后台运行一些代码是否是手动创建它而不是使用任何线程池的有效方法?我想要任何建议。谢谢!
  • @Loganathan 如果它是一个次要的“任务”,那么使用线程池是完全正确的。一个需要 10 秒的任务我不会再称之为次要了。创建线程时,您需要为线程创建和线程关闭支付开销。如果您的任务需要更长的时间,那么开销并不是很明显。对于一个 10 秒的任务,产生一个新线程应该是一件非常好的事情。
  • 我听说 Java8+ Collections.parellelStream() 在内部使用 'forkjoin common pool'。在这种情况下,如果一些耗时的任务使用Stream.forEach() 运行,那么它的性能也会很低。在那种情况下,如果我选择并行流,那么“如何避免这种延迟”现在是一个问题。我只是在使用 ForkJoinPool.commonPool() 的灵感,灵感来自它在并行流中的用法。
猜你喜欢
  • 1970-01-01
  • 2011-08-27
  • 1970-01-01
  • 2021-04-05
  • 2013-01-03
  • 1970-01-01
  • 2015-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多