一、线程池状态控制
使用AtomicInteger变量将工作线程数量与运行状态压缩在一起【其中高3位为线程池的运行状态,低29位为当前工作线程数】
运行状态
RUNNING:运行状态,可以处理新任务并执行队列中的任务【高三位为111】
SHUTDOWN:关闭状态,不接受新任务但是执行队列中的任务【高三位为000】
STOP:停止状态,不接受新任务也不处理队列中的任务并且会打断当前运行中任务【高三位为001】
TIDYING:整理状态,所有任务结束并且此时工作线程为0会进入结束状态【高三位为010】
TERMINATED:结束状态【高三位为011】
二、内部方法原理分析
构造方法
new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler),这是参数最全的构造方式也是推荐使用的构造方式,因此必须熟悉每一个参数的含义
corePoolSize:核心线程数,线程池的基本大小
maximumPoolSize:线程池最大数量,线程池允许创建的最大线程数【如果是无界队列,此参数意义不大】
keepAliveTime:线程空闲时最大存活时间
unit:keepAliveTime时间类型
BlockingQueue:用于保存等待执行的任务的阻塞队列,一般可以使用下面几种
ArrayBlockingQueue:基于数组实现的有界阻塞队列,FIFO(先进先出)对元素进行排序
LinkedBlockingQueue:一个基于链表实现的阻塞队列,不设置容量则为无界队列,FIFO(先进先出)对元素进行排序,吞吐量高
SynchrousQueue:一个不存储元素的阻塞队列,每个插入元素都必须等到另一个线程调用移出操作,否则插入操作会一直阻塞[相反也是],吞吐量高
PriorityBlockingQueue:优先级阻塞队列
还有很多拓展的队列,在JCTools中可以学习
threadFactory:用于设置创建线程的工厂
RejectedExecutionHandler:饱和策略,当线程池中的线程数超过线程池最大数量执行的拒绝策略
AbortPolicy:直接抛出异常
CallerRunsPolicy:直接调用所在线程执行任务
DiscardOldestPolicy:丢弃队列中最近的一个任务,并执行当前任务
DisacrdPolicy:不处理直接丢弃
自定义策略:实现RejectedExecutionHandler
往线程池中提交任务
execute(Runnable command):向线程池提交任务
工作流程
1、判断当前线程池中的工作线程数与corePoolSize的大小,如果比corePoolSize小,会创建一个新的线程用于执行任务,否则进入下一步
2、判断当前线程池中的任务队列是否已塞满,如果没有塞满直接将任务扔进队列中,否则进入下一步
3、判断当前线程池中的工作线程数是否达到了maximumPoolSize,未达到创建非核心线程执行任务,否则根据饱和策略处理
public void execute(Runnable command) {
if (command == null){
throw new NullPointerException();
}
// 这个值包含了线程池的状态以及当前线程池中工作线程的个数【使用ctl进行判断是必须先get防止并发问题】
int c = ctl.get();
// 如果工作线程数 < 核心线程数
if (workerCountOf(c) < corePoolSize) {
// 新建一个工作线程来运行任务,如果成功了,则直接返回【此过程会获取全局锁会消耗性能,因此线程池有个优化点,可以预热线程池,直接在启动时先创建线程(prestartAllCoreThreads)】
if (addWorker(command, true)){
return;
}
// 线程池已经shutdown,shutdown的线程池不再接收新任务
// workerCountOf(c) < corePoolSize判断后,由于并发别的线程先创建了worker线程,导致workerCount>=corePoolSize
// 获取当前线程池的状态【每次一旦需要进行线程池状态判断都需要先get】
c = ctl.get();
}
// RUNNING状态,则尝试把任务添加到任务队列
if (isRunning(c) && workQueue.offer(command)) {
// 重新检查
int recheck = ctl.get();
// 如果线程池已经不是running状态了,应该拒绝添加新任务,从workQueue中删除任务
if (!isRunning(recheck) && remove(command)){
// 拒绝任务
reject(command);
}
// 如果线程池是运行状态,或者从workQueue中删除任务失败(刚好有一个线程执行完毕,并消耗了这个任务),确保还有线程执行任务(只要有一个就够了)
else if (workerCountOf(recheck) == 0){
// 添加非核心线程
addWorker(null, false);
}
}
// 创建非核心线程来执行任务
else if (!addWorker(command, false)){
reject(command);
}
}
添加新的线程
addWorker(Runnable command,boolean core):根据core值判断创建的是核心线程还是非核心线程
addWorker的工作可分为两个部分
1、原子操作,判断是否可以创建worker,通过自旋、CAS等操作判断继续创建还是返回false,自旋周期一般很短[比锁效率高]
2、创建Worker启动线程执行任务
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
// 无限循环
for (;;) {
// 这个值包含了线程池的状态以及当前线程池中工作线程的个数
int c = ctl.get();
// 获取线程池的状态值
int rs = runStateOf(c);
// 线程池的state越小越是运行状态,runnbale=-1,shutdown=0,stop=1,tidying=2,terminated=3
// 如果线程池state已经至少是shutdown状态了
// rs == SHUTDOWN(隐含:rs>=SHUTDOWN)false情况:线程池状态已经超过shutdown,可能是stop、tidying、terminated其中一个,即线程池已经终止
// firstTask == null(隐含:rs==SHUTDOWN)false情况:firstTask不为空,rs==SHUTDOWN且firstTask不为空,return false,场景是在线程池已经shutdown后,还要添加新的任务,拒绝
// !workQueue.isEmpty()(隐含:rs==SHUTDOWN,firstTask==null)false情况:workQueue为空,当firstTask为空时是为了创建一个没有任务的线程,再从workQueue中获取任务,如果workQueue已经为空,那么就没有添加新worker线程的必要了
if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())){
return false;
}
for (;;) {
// 获取工作线程的数量
int wc = workerCountOf(c);
// 代表线程已经超标了
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)){
return false;
}
// 如果原子性增加工作线程数(+1)成功,代表创建线程成功
if (compareAndIncrementWorkerCount(c)){
break retry;
}
// 再次获取判断线程池状态
c = ctl.get();
if (runStateOf(c) != rs){
continue retry;
}
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建Worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 获取全局锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 再次判断线程池状态
int rs = runStateOf(ctl.get());
// 运行中状态或者shutdown状态但是任务为null代表可能队列中还有任务
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
// 线程正在运行
if (t.isAlive()){
throw new IllegalThreadStateException();
}
// 把worker加入到工作线程Set里面
workers.add(w);
int s = workers.size();
if (s > largestPoolSize){
largestPoolSize = s;
}
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 开始执行任务
t.start();
workerStarted = true;
}
}
} finally {
if (!workerStarted){
// 失败处理
addWorkerFailed(w);
}
}
return workerStarted;
}
线程真正运行的地方
runWorker(Worker w):执行任务
final void runWorker(Worker w) {
// 当前线程
Thread wt = Thread.currentThread();
// 任务
Runnable task = w.firstTask;
w.firstTask = null;
// 可以响应中断【在任务执行前是可以中断的】
w.unlock();
boolean completedAbruptly = true;
try {
// 任务不为null,或者队列中还存在任务
while (task != null || (task = getTask()) != null) {
// 上锁防止执行中的线程在shutdown时被中断
w.lock();
// Stop状态下直接中断
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()){
wt.interrupt()
}
try {
// 执行前置
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 开始正式运行任务
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
//任务执行完成后的钩子方法
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 处理退出后的worker
processWorkerExit(w, completedAbruptly);
}
}
获取需要被执行的task
getTask():从队列中获取任务执行
private Runnable getTask() {
// 是否超时
boolean timedOut = false;
for (;;) {
// 用于判断当前线程池的状态
int c = ctl.get();
int rs = runStateOf(c);
// 如果服务器状态为shutdown及以上
// 如果服务器状态为Stop之上并且工作队列是空的,直接workerNo减1并且返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 工作中的线程数
int wc = workerCountOf(c);
// 是否超时等待任务当大于核心线程数后
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 比最大线程数大,或者超时等待并且超时
// 工作线程数大于1或者任务队列为null
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果允许超时获取任务调用poll否则直接take
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 代表已经超时
timedOut = true;
} catch (InterruptedException retry) {
// 响应中断,重新开始,中断状态会被清除
timedOut = false;
}
}
}
worker线程退出
processWorkerExit():处理worker线程退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果是突然退出
if (completedAbruptly)
// worker线程数减1
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 把worker的完成任务数加到线程池的完成任务数
completedTaskCount += w.completedTasks;
// 工作者线程集合中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
// 判断线程池状态,尝试终止线程池
tryTerminate();
int c = ctl.get();
// 如果线程池是Stop之下的状态
if (runStateLessThan(c, STOP)) {
// 非突然停止
if (!completedAbruptly) {
// 如果min为0,即不需要维持核心线程数量,且workQueue不为空,至少保持一个线程
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 如果线程数量大于最少数量,直接返回,否则下面至少要addWorker一个
if (workerCountOf(c) >= min)
return;
}
// 添加一个没有firstTask的worker
// 只要worker是completedAbruptly突然终止的,或者线程数量小于要维护的数量,就新添一个worker线程,即使是shutdown状态
addWorker(null, false);
}
}
三、线程池带来的好处
1、降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗
2、提高响应速度,当任务到达时不用等待线程创建就能执行任务
3、提高线程的可管理性,线程是稀缺资源,如果无限制的创建不仅会消耗系统资源还会降低系统的稳定性
四、线程池类型
1、FixedThreadPool:固定线程数线程池,特点核心线程池与最大线程池大小一样并且线程不会被回收,没有一个任务就会创建一个线程去执行直到到达最大线程数
2、CachedThreadPool:缓存线程池,特点核心线程数为0,当有任务到来时会创建一个线程执行任务,如果存在空闲线程则不会创建,空闲线程超过60s会自动回收
3、SingleThreadExecutor:只存在一个线程的线程池,特点核心线程池与最大线程池大小都为1并且线程不会被回收[保证了task按照指定顺序被执行]
4、ScheduledThreadPoolExecutor:定时线程池,特点可以定时让线程执行任务
5、WorkStealingPool:窃取式、抢占式线程池,特点通过线程并行实现,此线程不能保证任务的顺序执行