引言

上面的几篇文章,我们整体描述了线程池中重要的类、接口和执行逻辑。ThreadPoolExecutor的几个参数如核心线程数、最大线程数、阻塞队列的选择和拒绝策略都需要我们在创建线程池时根据业务需要来认真衡量。JDK中提供了几个线程池的实现供我们选择,这篇文章,我们来看一下这几个线程池的优缺点。

newFixedThreadPool

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

这个方法返回一个核心线程数和最大线程数相同的线程池,这个数值就是参数中给定的值。并且由于最大线程数和核心线程数相同,没有多余的线程,所以线程的失效时间为零,也就是线程池中一直保持这些数量的线程。它的阻塞队列用的是LinkedBlockingQueue,这是一个长度为Integer.MAX_VALUE的队列,所以一直submit可能会造成队列的内存溢出。没有给定饱和策略,就是默认的AbortPolicy(抛出异常)。

newCachedThreadPool

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

这个线程池的最大线程数是Integer.MAX_VALUE,也就是会创建很多线程,它的队列用的是SynchronousQueue,该队列不会存储元素,每次提交一个任务,就必须得有一个线程来执行。所以这个线程池的缺点是无限创建线程可能导致内存不足。

newSingleThreadExecutor

  1. public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
  2. return new FinalizableDelegatedExecutorService
  3. (new ThreadPoolExecutor(1, 1,
  4. 0L, TimeUnit.MILLISECONDS,
  5. new LinkedBlockingQueue<Runnable>(),
  6. threadFactory));
  7. }

这个线程池的最大线程数和核心线程数都是1,没有失效时间,阻塞队列同样用的是LinkedBlockingQueue,同样会存在队列内存溢出的问题。