阿里开发手册为什么强制要求使用自定义线程池?
上面这条开发规范来自阿里巴巴的开发手册,且是一条强制规范,所以为啥阿里不允许使用Executors去创建线程池呢?
我们先来介绍一下Executors
Executors
在Java中,我们可以通过Executors类来方便地创建和管理线程池,Executors类提供了一系列工厂方法来创建不同类型的线程池。
以下是四种常见的使用Executors创建的线程:
-
newFixedThreadPool(int nThreads):创建一个固定大小的线程池,其中包含固定数量的线程。当线程池中的所有线程都在工作时,新任务会被放入队列中等待。
-
newCachedThreadPool():创建一个可根据需要创建新线程的线程池。如果有空闲线程,则将重用空闲线程;否则创建新线程。适用于执行很多短期异步任务的程序。
-
newSingleThreadExecutor():创建一个只有一个线程的线程池,保证任务按照指定顺序执行。
-
newScheduledThreadPool(int corePoolSize):创建一个可以执行定时任务的线程池,可以延迟执行任务或定期执行任务。
这四种线程池可以应付开发中绝大部分场景,但是这四种线程池都存在一定问题,这也是为什么不建议用Executors来创建线程池的原因。
存在的问题
我把这4种线程池按照线程类型分成了两类:
newFixedThreadPool 和 newSingleThreadPool
可以从源码发现这两种线程池在创建时对应的阻塞队列都采用了LinkedBlockingQueue,这个LinkedBlockingQueue是一种基于链表的阻塞队列,正是由于它基于链表,长度无限制,所以就算有再多的任务进来也不会塞满这个阻塞队列,最终就会导致任务过多产生OOM异常。
newCachedThreadPool 和 newScheduledThreadPool
这两种线程池都没有使用LinkedBlockingQueue作为阻塞队列了,也就不存在我之前讲的那种问题,但是它们的最大线程数为Integer.MAX_VALUE,这就说明就算任务数再多,它们也能通过创建新的线程去处理,而当java进程中线程达到一定多的数量,这个进程就容易发生崩溃。
以上就是对阿里不推荐使用Executors创建线程池这条规范具体原因的说明,那我们应该如何正确地创建线程池,又该如何正确地在自己项目中使用线程池呢?
自定义线程池:ThreadPoolExecutor
在项目中,我们应该使用ThreadPoolExecutor来创建线程池,使用ThreadPoolExecutor创建的线程池具有更高的灵活性,足以满足我们日常的开发。
分别介绍一下使用ThreadPoolExecutor来创建线程池时具体的参数:
-
corePoolSize 核心线程数,开发中具体设定的值与电脑CPU和代码逻辑有关。
-
maximumPoolSize 最大线程数,即核心线程数+临时线程数。
-
keepAliveTime 线程存活时间,用来指定临时线程的生存时间,生存时间内没有新任务,该线程会被释放,核心线程则不会释放。
-
unit 时间单位,临时线程生存时间的单位。
-
workQueue 阻塞队列,当没有空闲的核心线程时,新来的任务会加入此队列,队列满时会创建临时线程执行任务。
-
threadFactory 线程工厂,可以定制线程对象的创建,例如设置线程名字,是否是守护线程等。
-
handler 拒绝策略,当所有的线程都在繁忙,workQueue也放满时,就会触发拒绝策略。
如何在项目中正确使用自定义线程池,请参考:在真实项目开发场景中正确使用线程池