为什么不建议或不能用Executor去创建线程池?

发布时间 2023-08-06 13:25:29作者: 初仰

答:会存在内存溢出的风险。因为Executors中的核心方法,默认创建线程池的最大线程数是Integer.MAX_VALUE即int类型的最大值2^32-1,最大线程数允许这么多,几乎相当于不限制线程数,而这样的后果就是,如果瞬间请求量非常大,如果达到这个上限,没有任何服务器能够继续工作,肯定会抛出OOM异常。

Executors核心的方法有五个:

1)Executors.newCachedThreadPool

这个方法中maximumPoolSize最大可以至Integer.MAX_VALUE,是高度可伸缩的线程池,如果达到这个上限,相信没有任何服务器能够继续工作,肯定会抛出OOM异常。keepAliveTime默认为60秒,工作线程处于空闲状态,则回收工作线程。如果任务数量增加,再次创建出新线程处理任务。

2)Executors.newScheduledThreadPool

这个方法中maximumPoolSize最大可以至Integer.MAX_VALUE,也是是高度可伸缩的线程池,同样存在OOM问题。

它支持定时以及周期性的执行任务,它与newCachedThreadPool的区别是不回收工作线程。

3)Executors.newSingleThreadExecutor

作用:创建一个单线程的线程池,相当于单线程串行执行所有任务,保证按任务的提交顺序依次执行。当瞬间请求量非常大也会存在OOM问题。

4)Executors.newFixedThreadPool

输入的参数即是固定线程数,既是核心线程数也是最大线程数,不存在空闲线程,所以keepAliveTime等于0

 这里,输入的队列没有指明长度,其中LinkedBlockingQueue的构造方法:

 LinkedBlockingQueue是无界队列,最大长度也是Integer.MAX_VALUE即int类型的最大值2^32-1,使用这样的无界队列,如果瞬间请求量非常大,会有OOM风险。

5)Executors.newWorkStealingPool

JDK8引入的,作用:创建持有足够线程的线程池支持给定的并行度,并通过使用多个队列减少竞争,此构造方法中把CPU数量设置为默认的并行度:

禁止直接使用Executors创建线程池原因:
Executors.newCachedThreadPool和Executors.newScheduledThreadPool两个方法最大线程数为Integer.MAX_VALUE,如果达到上限,没有任务服务器可以继续工作,肯定会抛出OOM异常。
Executors.newSingleThreadExecutor和Executors.newFixedThreadPool两个方法的workQueue参数为new LinkedBlockingQueue<Runnable>(),容量为Integer.MAX_VALUE,如果瞬间请求非常大,会有OOM风险。
总结:以上5个核心方法除
Executors.newWorkStealingPool方法之外,其他方法都有OOM风险。

 
  参考:
阿里巴巴Java开发手册推荐线程池的创建方式 - 简书 (jianshu.com)
多线程高并发(五)线程池_newworkstealingpool有没有oom的情况_解决问题no解决代码问题的博客-CSDN博客