为什么不建议使用Executors创建线程池?
JDK为我们提供了Executors线程池工具类,里面有默认的线程池创建策略,大概有以下几种:
-
FixedThreadPool:线程池线程数量固定,即corePoolSize和maximumPoolSize数量一样。
-
SingleThreadPool:单个线程的线程池。
-
CachedThreadPool:初始核心线程数量为0,最大线程数量为Integer.MAX_VALUE,线程空闲时存活时间为60秒,并且它的阻塞队列为SynchronousQueue,它的初始长度为0,这会导致任务每次进来都会创建线程来执行,在线程空闲时,存活时间到了又会释放线程资源。
-
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创建线程池”这篇文章的所有内容,感谢各位的阅读!