1. 线程池定义
一个管理线程的池子或容器,是一种基于池化思想管理线程的工具。线程池的作用是管理线程、减少线程对象创建和销毁的性能开销。
2. 原理解析
2.1 七大核心参数
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数
- keepAliveTime 任务结束后线程的存活时间
- TimeUnit keepAliveTime的单位,常用s,ms
- BlockingQueue 任务缓冲队列
- ThreadFactory 线程工厂
- 拒绝策略 默认AbortPolicy,直接丢弃,并抛出异常
2.2 线程池的运行原理
线程池的任务调度都是由execute/submit方法完成的,在这个过程中,要检查线程池的运行状态、工作线程数、任务队列以及拒绝策略等,以决定接下来的执行流程是直接执行,还是缓冲执行,亦或是拒绝任务。其执行流程如下:
- 首先对线程数进行判断,如果工作线程数小于核心线程数,直接创建一个核心工作线程执行任务,否则尝试将任务添加到工作队列;
- 如果添加队列成功,判断一下工作线程数是否小于最大线程数maximumPoolSize,如果是就创建一个非核心工作线程执行任务,否则直接退出;
- 如果添加队列失败,尝试直接创建一个非核心工作线程执行任务,创建失败则交给拒绝策略来处理这个任务;
- 当一个线程完成任务的时候,它会从缓冲队列中取下一个任务来执行;
- 当一个线程空闲超过一定时间(keepAliveTime)时,线程池进行会判断:如果当前的工作线程数大于核心线程数corePoolSize,那么这个线程就会被终止。
3. 线程池的使用
3.1 JDK提供的几种创建线程池的方式
Executors 是JDK1.5开始提供的一个线程池工具类,支持直接调用方法创建不同的线程池,它们分别是:
1. Executors.newCacheThreadPool()
创建一个缓存线程池,可缓存线程以便重复使用。任务缓冲队列为SynchronousQueue,其容量为0,存取数据都要阻塞,来一个任务就创建一个工作线程执行任务;
2. Executors.newFixedThreadPool(10)
创建一个数量固定的线程池。任务缓冲队列为LinkedBlockingQueue,队列最大长度Integer.MAX_VALUE,使用不当会出现OOM问题。
3. Executors.newSingleThreadExecutor()
创建单个线程的线程池。由于只有一个线程,所以会不断复用,无法完全发挥CPU的性能,更适用于IO密集型任务。任务缓冲队列也是LinkedBlockingQueue。
4. Executors.newScheduledThreadPool(10)
创建一个定时周期性执行任务的线程池。任务缓冲队列使用延迟队列DelayedWorkQueue,特点是按照延迟时间的长短来排序,即下一个执行的任务排在最前面。
5. newSingleThreadScheduledExecutor()
单线程的定时任务线程池,相当于newScheduledThreadPool(1);6. newWorkStealingPool()
工作窃取线程池。Java8新增的创建线程池的方法,此线程池会并行处理任务,不能保证执行顺序,底层采用ForkJoinPool实现。
(阿里巴巴)不建议通过Executors 线程池去创建线程池,尤其是CachedThreadPool、FixedThreadPool和SingleThreadExecutor,因为CachedThreadPool的任务队列SynchronousQueue使用CAS自旋的方式保证线程安全,高并发下回产生大量CAS冲突自旋,发生CPU100%问题;FixedThreadPool和SingleThreadExecutor的任务队列默认长度为Integer.MAX_VALUE,可能会堆积大量的任务,从而导致 OOM。
3.2 线程池的4种拒绝策略
- AbortPolicy,抛出异常RejectedExecutionException拒绝提交任务;
- DiscardPolicy,直接抛弃任务,不做任何处理;
- DiscardOldestPolicy,去除任务队列中的第一个任务(最旧的),重新提交;
- CallerRunsPolicy,由调用execute方法提交任务的线程来执行这个任务;
3.3 线程池的生命周期
- running:线程池在运行,可添加执行任务,可执行队列任务
- shutdown:线程池关闭
- shutdown 平缓关闭:已经启动的任务全部执行完毕,等待队列中的阻塞任务会继续执行,同时不再接受新的任务
- shutdowNow 立即关闭:取消所有正在执行和未执行的任务(等同于stop)
- stop:线程池停止完毕,所有任务都已停止执行
- tidying:线程池整理,为接下来的终止做准备
- terminated:线程池终止,彻底关闭
3.4 线程池的继承结构
Executor和ExecutorService提供的方法