线程池的构造方式
- 两类构造方式
- 7种实现方法
- 7种线程池的具体使用
- FixedThreadPool
- CachedThreadPool
- SingleThreadExecutor
- ScheduledThreadPool
- SingleThreadScheduledExecutor
- newWorkStealingPool
- ThreadPoolExecutor
- 说明
- 总结
两类构造方式
在Java语言中,并发编程都是通过创建线程池来实现的。
而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景。
总体来说线程池的创建可以分为以下两类:
- 通过ThreadPoolExecutor手动创建线程池。
- 通过Executors执行器自动创建线程池。
7种实现方法
而以上两类创建线程池的方式,又有7种具体实现方法。这7种实现方法分别是:
- Executors.newFixedThreadPool
创建一个固定大小的线程池,可控制并发的线程数。超出的线程会在队列中等待。 - Executors.newCachedThreadPool
创建一个可缓存的线程池,若线程数超过处理所需。缓存一段时间后会回收,若线程数不够,则新建线程。 - Executors.newSingleThreadExecutor
创建单个线程数的线程池,它可以保证先进先出的执行顺序。 - Executors.newScheduledThreadPool
创建一个可以执行延迟任务的线程池。 - Executors.newSingleThreadScheduledExecutor
创建一个单线程的可以执行延迟任务的线程池。 - Executors.newWorkStealingPool
创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8添加】 - ThreadPoolExecutor
手动创建线程池的方式,它创建时最多可以设置7个参数。
7种线程池的具体使用
FixedThreadPool
创建一个固定大小的线程池,可控制并发线程数。
CachedThreadPool
创建一个可缓存的线程池,若线程数超过任务所需,那么多余的线程会被缓存一段时间后才被回收,若线程数不够,则会新建线程。
使用场景:CachedThreadPool是根据短时间的任务量来决定创建的线程数量的。所以它适合短时间内有突发大量任务的处理场景。
SingleThreadExecutor
创建单个线程的线程池,它可以保证先进先出的执行顺序。
单个线程的线程池有什么意义?
单个线程的线程池相比线程来说,它的优点有以下2个:
- 可以复用线程,即使是单个线程池,也可以复用线程。
- 提供了任务管理功能。单个线程池也拥有任务队列,在任务队列可以存储多个任务。这是线程无法实现的,并且当任务队列满了之后,可以执行拒绝策略。这些都是线程不具备的。
ScheduledThreadPool
创建一个可以执行延迟任务的线程池
SingleThreadScheduledExecutor
创建一个单线程的可以执行延迟任务的线程池
此线程池可以看作是ScheduledThreadPool的单线程池版本。
newWorkStealingPool
创建一个抢占式执行的线程池(任务执行顺序不确定)。此方法是JDK1.8版本新增的,因此只有在JDK1.8以上的程序中才能使用。
任务的执行顺序是不确定的,因为它是抢占式执行的。
ThreadPoolExecutor
是最原始、也是最推荐的手动创建线程池的方式,它在创建时最多提供7个参数可供设置。
ThreadPoolExecutor相比于其他创建线程池的优势在于它可以通过参数来控制最大任务数和拒绝策略,让线程池的执行更加透明和可控。
所以在阿里巴巴的《Java开发手册》是这样规定的,强制要求线程池不允许使用Executors去创建。而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明
Executors返回的线程池对象的弊端如下:
- FixedThreadPool和SingleThreadPool允许的请求队列长度为Integer.MAX_VALUE。可能会堆积大量的请求,从而导致OOM(内存溢出)。
- CachedThreadPool允许的创建线程数量为Integer.MAX_VALUE。可能会创建大量的线程,从而导致OOM。
总结
线程池的创建方式总共有以下7种:
- Executors.newFixedThreadPool创建一个固定大小的线程池,可控制并发的线程数。超出的线程会在队列中等待。
- Executors.newCachedThreadPool创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。
- Executors.newSingleThreadExecutor创建单个线程数的线程池,它可以保证先进先出的执行顺序。
- Executors.newScehduledThreadPool创建一个可以执行延迟任务的线程池。
- Executors.newSingleThreadScheduledExecutor创建一个单线程的可以执行延迟任务的线程池。
- Executors.newWorkStealingPool创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK1.8添加】
- ThreadPoolExecutor手动创建线程池的方式,它创建时最多可以设置7个参数,而线程池的创建推荐使用最后一种ThreadPoolExecutor的方式来创建,因为使用它可以明确线程池的运行规则,规避资源耗尽的风险。
参考资料:面试突击28:线程池有几种创建方式?推荐使用哪种?