前言
Executors类看起来功能还是比较强大的,又用到了工厂模式、又有比较强的扩展性,重要的是用起来还比较方便,如:
ExecutorService executor = Executors.newFixedThreadPool(nThreads) ;
即可创建一个固定大小的线程池。
但是为什么在阿里巴巴Java开发手册中也明确指出,不允许使用Executors创建线程池呢
主要原因
阿里巴巴Java开发手册建议避免直接使用Executors类来创建线程池,主要出于以下几个考虑:
-
默认的队列大小和最大线程数可能导致资源耗尽:
- FixedThreadPool和SingleThreadExecutor使用无界队列LinkedBlockingQueue,默认最大容量为Integer.MAX_VALUE。在高负载情况下,可能导致内存溢出。
- CachedThreadPool和ScheduledThreadPool允许创建的线程数量最大为Integer.MAX_VALUE,可能引发大量线程创建和内存溢出风险。
-
缺乏灵活性:
- Executors工厂方法创建的线程池参数预定义,不够灵活。直接使用ThreadPoolExecutor构造函数可以明确设置核心线程数、最大线程数、工作队列、拒绝策略等参数,更有利于根据业务需求进行优化。
-
隐藏了复杂性:
- Executors的便捷性隐藏了线程池内部的复杂性和细节,可能导致开发者对线程池运行机制理解不足,产生意外异常。
-
性能问题:
- 使用无界队列可能增加内存消耗,降低系统稳定性。任务过多可能导致线程上下文切换频繁,影响性能。
因此,建议直接使用ThreadPoolExecutor构造函数创建线程池,能更好地理解线程池工作原理,根据需求合理配置,避免潜在风险,提高系统稳定性和性能。虽然增加了编码复杂度,但获得更好的控制力和安全性是值得的。
四大线程池
线程池类型 | 核心线程数固定 | 最大线程数 | 工作队列 | 适用场景 |
---|---|---|---|---|
FixedThreadPool | 是 | 固定 | LinkedBlockingQueue(无界队列) | 适用于执行长期的任务,控制线程最大数量 |
SingleThreadExecutor | 是 | 1 | LinkedBlockingQueue(无界队列) | 适用于需要顺序执行任务的场景 |
CachedThreadPool | 不是 | Integer.MAX_VALUE | SynchronousQueue(同步队列) | 适用于执行大量短期异步任务的场景 |
ScheduledThreadPool | 不是 | Integer.MAX_VALUE | DelayedWorkQueue(延迟队列) | 适用于需要定时执行或周期性执行的任务 |
以上是对四种线程池类型的简要比较,以帮助选择最适合特定需求的线程池类型。