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

所以我有一个程序,产生线程(〜5-150),执行一堆任务。 最初我使用了一个FixedThreadPool因为这个类似的问题表明它们更适合更长寿命的任务,而且由于我对multithreading的知识非常有限,所以我认为线程的平均寿命(几分钟)“ 长寿 ”。

不过,我最近添加了产生额外线程的function,这样做使我超出了我设置的线程限制。 在这种情况下,是否会更好地猜测和增加我可以允许的线程数或切换到CachedThreadPool所以我没有浪费线程?

初步尝试它们,似乎没有什么区别,所以我倾向于使用CachedThreadPool来避免浪费。 然而,线程的寿命是否意味着我应该select一个FixedThreadPool并只处理未使用的线程? 这个问题看起来好像那些额外的线程没有被浪费,但是我希望澄清。

一个CachedThreadPool正是你应该使用你的情况,因为使用长期运行的线程没有负面的后果。 关于CachedThreadPools适用于短任务的java文档中的注释仅仅表明它们特别适用于这种情况,而不是它们不能或不应该用于涉及长时间运行任务的任务。

为了进一步阐述, Executors.newCachedThreadPool和Executors.newFixedThreadPool都是由相同的线程池实现(至less在JDK打开的时候)用不同的参数来支持的。 线程的最小值,最大值,线程closures时间和队列types的区别。

 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确实有其优势,因为您可以在执行器服务中提交任意数量的任务,同时知道线程数量将保持在您指定的级别。 如果你明确地想要增加线程的数量,那么这不是合适的select。

然而,这并不意味着你在CachedThreadPool中可能遇到的一个问题就是限制同时运行的线程的数量。 CachedThreadPool不会限制它们,所以你可能需要编写你自己的代码来确保你不会运行太多的线程。 这实际上取决于应用程序的devise以及如何将任务提交给执行程序服务。

FixedThreadPoolCachedThreadPool都是高负载应用程序中的CachedThreadPool

CachedThreadPoolFixedThreadPool更危险

如果您的应用程序负载很重,并且要求低延迟,那么由于以下缺点,最好摆脱这两种select

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

既然你们知道这两个都是罪恶,小恶就行不通了。 首选ThreadPoolExecutor ,它提供了对许多参数的细粒度控制。

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

所以我有一个程序,产生线程(〜5-150),执行一堆任务。

你确定你知道你的操作系统和select的硬件是如何处理线程的吗? Java如何将线程映射到操作系统线程,如何将线程映射到CPU线程等? 我在问,因为在ONE JRE中创build150个线程只有在下面有大量的CPU核心/线程时才有意义,这很可能不是这种情况。 根据使用的操作系统和RAM,创build多于n个线程甚至可能导致您的JRE由于OOM错误而终止。 所以你应该真正的区分线程和工作线程,你甚至可以处理多less工作等等。

这就是CachedThreadPool的问题:在实际上无法运行的线程中排队长时间运行的工作是没有意义的,因为只有2个CPU内核能够处理这些线程。 如果最终有150个预定线程,则可能会为Java和OS中使用的调度程序并行处理它们而创build大量不必要的开销。 如果你只有2个CPU核心,这是不可能的,除非你的线程一直在等待I / O。 但即使在这种情况下,很multithreading会创build大量的I / O …

这个问题不会发生在用例如2 + n个线程创build的FixedThreadPool中,其中n当然是合理的,因为硬件和操作系统资源的使用对pipe理无法运行的线程的开销要小得多。