FixedThreadPool vs CachedThreadPool:两个邪恶中较小的一个

时间:2013-07-30 21:05:09

标签: java multithreading threadpool executorservice java.util.concurrent

所以我有一个程序产生线程(~5-150)执行一堆任务。最初我使用FixedThreadPool,因为this similar question建议他们更适合长寿任务,而且我对多线程的知识非常有限,我认为线程的平均寿命(几分钟)“ long住”。

但是,我最近添加了生成其他线程的功能,这样做会使我超出我设置的线程限制。在这种情况下,最好猜测并增加我可以允许的线程数或切换到CachedThreadPool所以我没有浪费的线程吗?

初步尝试这两种方法,似乎似乎不同,所以我倾向于选择CachedThreadPool以避免浪费。但是,线程的生命周期是否意味着我应该选择FixedThreadPool来处理未使用的线程? This question使得看起来这些额外的线程没有浪费,但我希望澄清。

3 个答案:

答案 0 :(得分:97)

CachedThreadPool正是您应该根据自己的情况使用的,因为对于长时间运行的线程使用一个没有任何负面后果。关于CachedThreadPools的Java文档中适用于简短任务的注释仅表明它们特别适用于此类情况,而不是它们不能或不应该用于涉及长时间运行任务的任务。

进一步说明,Executors.newCachedThreadPoolExecutors.newFixedThreadPool都由相同的线程池实现(至少在开放的JDK中)支持,只是使用不同的参数。差异只是它们的线程最小值,最大值,线程终止时间和队列类型。

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>());
 }

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<Runnable>());
}

当你确实希望使用固定数量的线程时,FixedThreadPool确实有其优势,因为这样你就可以向执行程序服务提交任意数量的任务,同时知道线程数将保持在这个级别你指定了。如果您明确希望增加线程数,那么这不是合适的选择。

但这意味着您可能对CachedThreadPool提出的一个问题是限制并发运行的线程数。 CachedThreadPool不会为您限制它们,因此您可能需要编写自己的代码以确保不会运行太多线程。这实际上取决于应用程序的设计以及如何将任务提交给执行程序服务。

答案 1 :(得分:34)

FixedThreadPoolCachedThreadPool都是高负载应用程序中的祸害。

CachedThreadPoolFixedThreadPool

更危险

如果您的应用程序是高负载的&amp;要求低延迟,由于以下缺点,最好摆脱两种选择

  1. 任务队列的无限性:可能导致内存不足或高延迟
  2. 长时间运行的线程将导致CachedThreadPool在创建线程
  3. 时失控

    既然你知道两者都是邪恶的,那么较小的邪恶就不会有好处。首选ThreadPoolExecutor,它提供对许多参数的精细控制。

    1. 将任务队列设置为有界队列以便更好地控制
    2. 拥有正确的RejectionHandler - 您自己的RejectionHandler或JDK提供的默认处理程序
    3. 如果您在完成任务之前/之后有任何事情要做,请覆盖beforeExecute(Thread, Runnable)afterExecute(Runnable, Throwable)
    4. 如果需要进行线程自定义,则覆盖ThreadFactory
    5. 在运行时动态控制线程池大小(相关SE问题:Dynamic Thread Pool

答案 2 :(得分:5)

  

所以我有一个生成线程(~5-150)的程序,它执行一系列任务。

您确定了解操作系统和所选硬件实际处理线程的方式吗? Java如何将线程映射到OS线程,如何将线程映射到CPU线程等?我问,因为在ONE JRE中创建150个线程只有在下面有大量的CPU核心/线程时才有意义,但很可能并非如此。根据所使用的操作系统和RAM,创建超过n个线程甚至可能导致JRE因OOM错误而终止。所以你应该真正区分这些线程的线程和工作,你甚至能够处理多少工作等。

这就是CachedThreadPool的问题:在实际无法运行的线程中排队长时间运行的工作是没有意义的,因为你只有2个CPU内核能够处理这些线程。如果最终得到150个调度线程,则可能会为Java和OS中使用的调度程序创建大量不必要的开销,以便同时处理它们。如果你只有2个CPU核心,这是完全不可能的,除非你的线程一直在等待I / O或者这样。但即使在这种情况下,很多线程也会产生很多I / O ......

使用FixedThreadPool创建的问题不会发生,例如2 + n个线程,其中n当然合理地低,因为使用该硬件和操作系统资源可以用于管理无法运行的线程的开销更少。