在学习线程时,我们了解了创建线程的不同方式,比如继承Thread类、实现Runnable接口、Callable接口等。针对线程池的使用,我们提供了两种构造线程池的方法:
方法一:
通过ThreadPoolExecutor构造函数来创建(首选)
这是JDK中最核心的线程池工具类,提供了丰富的可设置的线程池构造参数,如设置线程池大小、等待队列、非核心线程存活时间、创建线程的工厂类、拒绝策略等。
通过构造方法,可以给整个线程池设置大小、等待队列、非核心线程存活时间、创建线程的工厂类、拒绝策略等。具体参数描述可见
第六问
,该参数与线程池中的对应关系可见下图。
方法二:
通过 Executor 框架的工具类 Executors 来创建(不推荐)
Executors 是java并发工具包中的静态工厂类,提供了丰富的创造线程池的方法,但不推荐使用。
为何很多大厂都禁止使用Executors 创建线程池呢?
大部分公司已经不建议采用Executors提供的方法创建线程池了。如果深入研究Executors方法的底层实现,就会发现原因。像FixedThreadPool和SingleThreadExecutor这两个方法内使用的是无界的LinkedBlockingQueue存储任务,任务队列最大长度为Integer.MAX_VALUE,这样可能会堆积大量的请求,从而导致OOM。
而CachedThreadPool使用的是同步队列SynchronousQueue,允许创建的线程数量也为Integer.MAX_VALUE,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致OOM。其他方法所提供的均是这种
无界任务队列
,在高并发场景下导致OOM的风险很大。