概述
- ExecutorService:是线程池最低本的接口
- ScheduledExecutorService:在基础接口ExecutorService上拓展了任务调度的功能
- ThreadPoolExecutor:是最基础的线程池实现类
- ScheduledThreadPoolExecutor:最基础的带有任务调度功能的线程池实现
ThreadPoolExecutor
线程池状态
ThreadPoolExecutor使用int的高3位来表示线程池的状态,低29位表示线程数量。
状态名 | 高3位 | 接收新任务 | 处理阻塞队列任务 | 说明 |
RUNNING | 111 | Y | Y | 线程池创建运行,接收处理新任务和队列任务 |
SHUTDOWN | 000 | N | N | 不会接收新的任务,但是会处理阻塞队列剩余的任务 |
STOP | 001 | N | N | 会中断正在执行的任务,并抛弃阻塞队列任务 |
TIDYING | 010 | - | - | 任务全执行完毕,活动线程位0即将进入终结 |
TERMINATED | 011 | - | - | 终结状态 |
从数字上比较,TERMINATED>TIDYING>STOP>SHUTDOWN>RUNNING(由于是高3位,RUNNING 111 的第一个1代表符号位,负数)
为什么会用一个整数来记录线程池状态和线程数量这两种信息呢?
这么做的目的是为了将线程池状态和线程数“合二为一”存储在一个原子变量中,就可以用一次CAS原子操作进行赋值了。
主要构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler,
ThreadFactory threadFactory) {
......
}
- corePoolSize:核心线程数(最多保留的线程数)
- maximumPoolSize:最大线程数
- keepAliveTime:生存时间,针对救急线程
- unit:TimeUnit时间单位,针对救急线程
- workQueue:阻塞队列
- threadFactory:线程工厂(可以定义线程名称)
- handler:拒绝策略
当有任务进入线程池之后,首先会分配核心线程进行处理,当核心线程全部处于工作状态后,接收新的任务将会被放入队列中,当队列也满了之后,线程池会启用救急线程来承担更多的任务。在此之后仍然有任务进来,才会触发拒绝策略。
救急线程在执行完任务后就会被销毁掉,不会被线程池所维持,而核心线程是有生存时间的。
特点如下:
- 线程池创建之后并不是马上创建任务线程,当一个任务提交给线程池之后,线程池才会创建一个新的线程来执行任务。
- 当线程数达到corePoolSize后,此时线程池中没有空闲线程,这时再加入任务,新加的任务会被加入workQueue队列等待,直到有任务线程被释放出来。
- 如果队列选择了有界队列,那么任务超过了队列大小时,会创建maximumPoolSize - corePoolSize数目线程来救急。
- 当所有线程数达到maximumPoolSize之后人有新任务这时会执行拒绝策略。
- 当高峰期过去之后,超过了corePookSize的救济线程如果一段时间没有任务做,需要结束节省资源,这个时间长度由keepAlive和timeUnit来控制。
拒绝策略
- AbortPolicy让调用者抛出RejectedException异常,这是默认策略
- CallerRunsPolicy让调用者运行任务
- DiscardPolicy放弃本次任务
- DIscardOldestPolicy放弃队列种最早加入的任务,当前任务加入队列