Java 为什么ForkJoinPool.commonPool().execute(runnable)运行线程需要更多时间

Java 为什么ForkJoinPool.commonPool().execute(runnable)运行线程需要更多时间,java,multithreading,performance,threadpool,forkjoinpool,Java,Multithreading,Performance,Threadpool,Forkjoinpool,我正在使用ForkJoinPool.commonPool().execute(runnable)作为在我的应用程序的许多地方生成线程的简便方法。但是在一个特定的调用过程中,调用线程中可运行的代码需要更多的时间(超过10秒)。原因可能是什么?如何避免这种情况 编辑:根据@ben的回答,避免线程池中长时间运行的进程似乎是解决方案。手动创建新线程解决了我的问题,而不是使用公共线程池 所以经过一些快速测试,我发现了问题。请看以下示例代码: List<Runnable> runnables =

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


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

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

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();
}
List runnables=new ArrayList();
对于(int i=0;i<20;++i)
{
runnables.add(()->{
System.out.println(“可运行启动”);
尝试
{
睡眠(10000);
}
捕捉(中断异常e)
{
}
System.out.println(“可运行端”);
});
}
for(可运行运行运行:可运行)
{
//ForkJoinPool.commonPool().execute(run);
//新线程(run.start();
}
在两行中的一行中添加注释。 我们创建了许多可运行程序,它们发送消息,闲置10秒,然后再次发送消息。很简单

当为每个线程使用线程时,所有可运行程序发送
Runnable start
10s pass,所有可运行程序发送
Runnable end

当使用commonPool()时,只有一部分发送
Runnable start
10s密码,它们发送
Runnable end
,另一组发送
Runnable start
,直到它们全部完成

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


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

您在许多地方都使用公共池吗?默认情况下,它的线程数与您的内核数相同,因此很容易填充。您的池中可能同时填充了太多的任务。除此之外,我不完全确定为什么它会比生成线程慢,因为在内部它只是一个静态构造的线程池,不应该慢(而且决不能慢10秒)@ben我碰巧延迟到了近10秒。@kayaman是的。我认为使用公共池将是一种有效的方法,因为它知道如何使用内核,并将利用这些内核。@Loganathan不使用
@anyone
,因为它的工作方式就像
@noone
,即没有人得到通知。当您不需要线程池功能,并且任务需要一秒钟或更长时间时,只需生成一个新线程,因为没有任何好处。线程池让您可以控制运行任务的数量,并且每个任务的开销要小得多(我想,创建线程需要花费很多微秒)。不,这个故事的寓意是,除非您了解commonPool的工作原理,否则不要使用它。创建自己的执行器,并在其中放入所需的线程数。这是一种更好的方式。我会编辑。@你们两个都会在我的应用程序的许多地方生成一个线程,在后台运行一些代码。手动创建它而不是使用任何线程池是一种有效的方法吗?我想要任何关于这方面的建议。谢谢@Loganathan如果这是一个次要的“任务”,那么使用线程池是完全正确的。一项耗时10秒的任务不再是我所说的次要任务了。创建线程时,您将为线程创建和线程关闭支付开销。如果您的任务需要更长的时间,那么开销实际上是不可察觉的。对于10秒的任务来说,生成一个新线程应该是一件非常好的事情。我听说过Java8+
Collections.parellelStream()
在内部使用“forkjoin公共池”。在这种情况下,如果一些耗时的任务使用
Stream.forEach()
运行,其性能也会很低。在这种情况下,如果我选择并行流,“如何避免这种延迟”是现在的问题。我刚刚使用了
ForkJoinPool.commonPool()
,灵感来自于它在并行流中的用法。