为什么不建议使用Executors创建线程池?

JDK为我们提供了Executors线程池工具类,里面有默认的线程池创建策略,大概有以下几种:

  1. FixedThreadPool:线程池线程数量固定,即corePoolSize和maximumPoolSize数量一样。

  2. SingleThreadPool:单个线程的线程池。

  3. CachedThreadPool:初始核心线程数量为0,最大线程数量为Integer.MAX_VALUE,线程空闲时存活时间为60秒,并且它的阻塞队列为SynchronousQueue,它的初始长度为0,这会导致任务每次进来都会创建线程来执行,在线程空闲时,存活时间到了又会释放线程资源。

  4. ScheduledThreadPool:创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。

虽然用Executors工具类方便,但是阿里巴巴开发手册强制不允许使用Executors来创建线程池,原因在于:(摘自阿里编码规约)

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,

规避资源耗尽的风险。说明:Executors各个方法的弊端:newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请

求处理队列可能会耗费非常大的内存,甚至OOM。newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数

是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

我们从JDK源码中寻找一波答案:java.util.concurrent.Executors:

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

// SingleThreadPool
public static ExecutorService newSingleThreadExecutor() {
  return new FinalizableDelegatedExecutorService
    (new ThreadPoolExecutor(1, 1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()));
}

// CachedThreadPool
public static ExecutorService newCachedThreadPool() {
  // 允许创建线程数为Integer.MAX_VALUE
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                 60L, TimeUnit.SECONDS,
                 new SynchronousQueue<Runnable>());
}

// ScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
  // 允许创建线程数为Integer.MAX_VALUE
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
       new DelayedWorkQueue());
  }

  

public LinkedBlockingQueue() {
  // 允许队列长度最大为Integer.MAX_VALUE
  this(Integer.MAX_VALUE);
}

从JDK源码可看出,Executors工具类无非是把一些特定参数进行了封装,并提供一些方法供我们调用而已,我们并不能灵活地填写参数,策略过于简单,不够友好。

CachedThreadPool和ScheduledThreadPool最大线程数为Integer.MAX_VALUE,如果线程无限地创建,会造成OOM异常。

LinkedBlockingQueue基于链表的FIFO队列,是无界的,默认大小是Integer.MAX_VALUE,因此FixedThreadPool和SingleThreadPool的阻塞队列长度为Integer.MAX_VALUE,如果此时队列被无限地堆积任务,会造成OOM异常。

以上是“为什么不建议使用Executors创建线程池”这篇文章的所有内容,感谢各位的阅读!

 

posted @ 2021-05-31 14:30  江南大才子  阅读(545)  评论(0编辑  收藏  举报