目录
参考文章
线程池优势
- 降低资源消耗,复用已有线程
- 控制并发数量
- 提高响应速度,复用已有线程
- 方便管理
总体设计
- 采用生产者-消费者模型将任务和线程解藕,采用阻塞队列缓冲任务
- Executor框架完成线程的调配和任务的执行部分
- ExecutorService接口增加了一些能力:(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,比如停止线程池的运行。
- AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务
源码解析
相关资源控制
线程池相关信息管理
// 高3位存储线程池的运行状态,低29位保存线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static int runStateOf(int c) { return c & ~CAPACITY; } //计算当前运行状态
private static int workerCountOf(int c) { return c & CAPACITY; } //计算当前线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; } //通过状态和线程数生成ctl
ThreadPoolExecutor的5种运行状态
ThreadPoolExecutor的生命周期转换
阻塞队列
- 两个附加的操作是:
- 在队列为空时,获取元素的线程会等待队列变为非空,从而获取元素
- 当队列满时,存储元素的线程会等待队列可用,从而存储元素
拒绝策略
线程创建执行任务或线程在任务队列取任务执行
- submit -> execute -> addWorker -> runWorker -> getTask
submit函数
execute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// clt记录着runState和workerCount
int c = ctl.get();
//workerCountOf方法取出低29位的值,表示当前活动的线程数
//然后拿线程数和 核心线程数做比较
if (workerCountOf(c) < corePoolSize) {
// 如果活动线程数<核心线程数
// addWorker中的第二个参数表示限制添加线程的数量是根据corePoolSize来判断还是maximumPoolSize来判断
if (addWorker(command, true))
// 如果成功则返回
return;
// 如果失败则重新获取 runState和 workerCount
c = ctl.get();
}
// 如果当前线程池是运行状态并且任务添加到队列成功
if (isRunning(c) && workQueue.offer(command)) {
// 重新获取 runState和 workerCount
int recheck = ctl.get();
// 如果不是运行状态并且
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
//第一个参数为null,表示在线程池中创建一个线程,但不去启动
// 第二个参数为false,将线程池的有限线程数量的上限设置为maximumPoolSize
addWorker(null, false);
}
//再次调用addWorker方法,但第二个参数传入为false,将线程池的有限线程数量的上限设置为maximumPoolSize
else if (!addWorker(command, false))
//如果失败则拒绝该任务
reject(command);
}
addWorker方法
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
// 获取运行状态
int rs = runStateOf(c);
// 如果状态值 >= SHUTDOWN (不接新任务&不处理队列任务)
// 并且!(rs为SHUTDOWN 且 firsTask为空 且 阻塞队列不为空)
// 判断是否有未完成的任务
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
// 返回false
return false;
for (;;) {
//获取线程数wc
int wc = workerCountOf(c);
// 如果wc>容量 || core如果为true表示根据corePoolSize来比较,否则为maximumPoolSize
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 自增workerCount(原子操作)
if (compareAndIncrementWorkerCount(c))
// 如果增加成功,则跳出
break retry;
// wc增加失败,则再次获取runState
c = ctl.get(); // Re-read ctl
// 如果当前的运行状态不等于rs,说明状态已被改变,返回重新执行
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 根据firstTask来创建Worker对象
w = new Worker(firstTask);
// 根据worker创建一个线程
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 获取runState
int rs = runStateOf(ctl.get());
// 如果rs小于SHUTDOWN(处于运行)或者(rs=SHUTDOWN && firstTask == null)
// firstTask == null证明只新建线程而不执行任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 如果t活着就抛异常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 否则加入worker(HashSet)
//workers包含池中的所有工作线程。仅在持有mainLock时访问。
workers.add(w);
// 获取工作线程数量
int s = workers.size();
//largestPoolSize记录着线程池中出现过的最大线程数量
if (s > largestPoolSize)
// 如果 s比它还要大,则将s赋值给它
largestPoolSize = s;
// worker的添加工作状态改为true
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 如果worker的添加工作完成
if (workerAdded) {
// 启动线程,
t.start();// 等同于启动worker本身,调用worker自身的run方法
// 修改线程启动状态
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
// 返回线启动状态
return workerStarted;
}
runWorker方法
final void runWorker(Worker w) {
// 拿到当前线程
Thread wt = Thread.currentThread();
// 拿到初始化时提交的任务
Runnable task = w.firstTask;
// 将Worker.firstTask置空 并且释放锁
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 如果task或者getTask不为空,则一直循环
while (task != null || (task = getTask()) != null) {
// 加锁
w.lock();
// 如果线程池状态>=STOP(停止) 或者 (线程中断且线程池状态>=STOP)且当前线程没有中断
// 其实就是保证两点:
// 1. 线程池没有停止
// 2. 保证线程没有中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
// 中断当前线程
wt.interrupt();
try {
// 任务执行前
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 执行run方法(Runable对象)
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置空, 完成任务++, 释放锁
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 退出工作
processWorkerExit(w, completedAbruptly);
}
}
getTask方法
private Runnable getTask() {
boolean timedOut = false;
//无限循环
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查队列是否为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
//获取运行线程数,根据allowCoreThreadTimeOut决定是否允许定时等待
int wc = workerCountOf(c);
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//线程超时并且队列为空时通过CAS将实际运行线程数减1
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;
//继续循环,并且置超时标识为true
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
Worker线程管理
Worker内部类
- 继承自AQS,实现了Runnable接口
- 线程池使用HashSet去持有线程的引用,这样可以通过添加引用、移除引用这样的操作来控制线程的生命周期
- 一直运行runWorker()方法
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// worker运行的线程
final Thread thread;
// 包装的任务
Runnable firstTask;
// 线程完成的任务数量
volatile long completedTasks;
// 构造函数
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
// run函数
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
Worker线程回收
- 将线程引用移出线程池,由JVM回收
try {
while (task != null || (task = getTask()) != null) {
//执行任务
}
} finally {
processWorkerExit(w, completedAbruptly);//获取不到任务时,主动回收自己
}
判断线程是否在运行
- 线程运行期间会加锁
创建线程池参数
五个必须
- int corePoolSize:该线程池中核心线程数最大值
- 核心线程:核心线程默认情况下会一直存在于线程池中,即使这个核心线程什么都不干(铁饭碗),
- 非核心线程:如果长时间的闲置,就会被销毁(临时工)
- int maximumPoolSize:该线程池中线程总数最大值 。
该值等于核心线程数量 + 非核心线程数量。
- long keepAliveTime:非核心线程闲置超时时长,默认情况下只有当线程池中的线程数大于corePoolSize时才会起作用
- TimeUnit unit:keepAliveTime的单位。
- BlockingQueue workQueue:阻塞队列,维护着等待执行的Runnable任务对象。后面详细介绍
两个非必须参数
- RejectedExecutionHandler handler:拒绝策略
- ThreadFactory threadFactory:线程工厂,统一在创建线程时设置一些参数
Executors自带线程池
newCachedThreadPool
- 特点:线程不够的话可以无限增加
- 使用SynchronousQueue:不存储元素
- 核心线程数为:0
- 程池没有最大线程数量限制,所以当大量线程蜂拥而至,会造成资源耗尽
newFixedThreadPool
- 特点:线程不销毁,一直等待
- 使用LinkedBlockingQueue:无界队列
- corePoolSize == maximumPoolSize
- 阻塞队列无限大造成OOM
newScheduledThreadPool
- DelayedWorkQueue:无限长的
- 初始化值为核心线程数,最大线程数为Integer.MAX_VALUE
- 提交延时任务
newSingleThreadExecutor
- 特点:保证多任务按顺序执行
- 缺点:单线程,高并发业务下性能差
- LinkedBlockingQueue
- corePoolSize == maximumPoolSize = 1
常见问题
- 核心线程和非核心线程的区别
- 什么时候会去任务队列拿任务?
- 如果提交了新任务,但是有空闲的线程,这个任务是由新创建的线程执行还是由空闲的线程执行?
- 线程数量没有达到核心线程数总是会新建线程去执行任务
- 怎么保证核心线程不被销毁?
- 线程池的数量>核心线程数,且拿不到任务了,则线程结束
- 线程池的数量<=核心线程数,调用阻塞队列的take()方法,拿不到任务会阻塞