线程池使用约定
首先,线程在我们程序员的世界里可以说是无处不在,简单来说,线程池便是将线程进行池化,方便对有限的线程资源进行统一调度和管理。在 Java Web 的项目中,我们队线程池有一些这样的使用约定。
什么情况下使用线程池
执行任务的数量极大
单个任务执行的时间很短,并且可以多个并行执行时
执行的任务需要限流排队时
需要并行执行任务时
……
太多了数不过来,也有时候是上面多个情况的组合。
禁止使用 Executors 创建线程池
这条肯定不是规范,而是一条编码规约(特定规范的约定),为了避免线程池参数不规范从而导致的内存溢出( OOM)问题。
主要还是由于 Executors 创建线程池对象的方法,主要有三种:
Executors#newCachedThreadPool => 创建可缓存的线程池
Executors#newSingleThreadExecutor => 创建单线程的线程池
Executors#newFixedThreadPool => 创建固定长度的线程池
其中 CachedThreadPool 的最大线程数是 Integer.MAX_VALUE,可以认为是无限的,这就很容易失控,导致线程堆积,CPU 占用 100% 后的 OOM。
第二种 newSingleThreadExecutor 线程池是单线程,加上一个 workQueue 队列(使用 LinkedBlockingQueue),也有不完善的问题,如果单线程执行太慢或者发生阻塞,队列里面的任务将会持续堆积,知道发生 OOM 异常。对,看出来了,这个线程池没有队列的拒绝策略功能。
第三种 newFixedThreadPool 固定长度线程池中,队列也是一个无界队列 LinkedBlockingQueue,所以在资源有限的情况下,没有线程队列的拒绝策略是很可怕的。
这里只是简单说一些,如果想了解详情,可以自行搜索圈子内的一篇文章《为什么阿里巴巴要禁用 Executors 创建线程池?》。
结论
就是使用禁止使用 Executors 去创建线程池,推荐通过自己创建 ThreadPoolExecutor 的方式来使用线程池。
使用 Spring Boot 创建线程池