我们工作中肯定避免不了使用线程的情况,而常规的new一个线程的方式,在线程使用情况较多的场景下却是不太满足需求,一方面容易造成线程资源的耗费,一方面也是不方便统一管理无法复用,而线程池的出现就很好的解决了这些问题,其中使用最多的就是ThreadPoolExecutor。
开始源码之前,得先知道ThreadPoolExecutor的几种状态,ThreadPoolExecutor的状态和数量是通过一个Integer进行记录的,高3位记录了ThreadPoolExecutor的状态,其余的位数是用来记录线程数量。这个方式在java源码中很常见,他们很多时候都会根据位数去处理多个状态的情况,而不是重新在定义一个新的变量。
java
//记录当前线程状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//掩码位数
private static final int COUNT_BITS = Integer.SIZE - 3;
//线程最大个数
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//接受新任务并且处理阻塞队列的任务
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
//拒绝新任务但是处理阻塞队列里的任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
//拒绝新任务并且抛弃阻塞队列里的任务,同时会中断正在处理的任务
private static final int STOP = 1 << COUNT_BITS;
//所有任务都执行完,包括阻塞队列里的任务后当前线程池的活动线程为0
private static final int TIDYING = 2 << COUNT_BITS;
//终止状态
private static final int TERMINATED = 3 << COUNT_BITS;
查看构造函数
java
/**
* 工作队列
*/
private final BlockingQueue<Runnable> workQueue;
/**
* 线程池工厂
*/
private volatile ThreadFactory threadFactory;
/**
* 饱和策略
*/
private volatile RejectedExecutionHandler handler;
/**
* 空闲线程超时时间
*/
private volatile long keepAliveTime;
/**
* 核心线程是否允许超时
*/
private volatile boolean allowCoreThreadTimeOut;
/**
* 核心线程数
*/
private volatile int corePoolSize;
/**
* 最大线程数
*/
private volatile int maximumPoolSize;
/**
* 默认饱和策略处理器,默认是抛出饱和异常
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
工作上比较常用的应该是核心线程数,最大线程数和饱和策略的配置,要想让ThreadPoolExecutor使用不同的情况则需要配置适合的工作队列,各类型的线程池本质上来说还是队列的选型不同。
查看最核心的execute方法
java
public void execute(Runnable command) {
//为空则抛出空指针异常
if (command == null)
throw new NullPointerException();
//获取当前线程池状态和线程数
int c = ctl.get();
//获取线程个数,判断当前线程个数是否小于核心线程数
if (workerCountOf(c) < corePoolSize) {
//开启新线程
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果线程池是运行状态,则添加任务到阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
//二次校验
int recheck = ctl.get();
//如果当前线程池不为运行状态,则删除任务,执行饱和策略
if (! isRunning(recheck) && remove(command))
reject(command);
//如果当前的线程池中没有工作线程,则创建一个新的线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果队列已满,则添加新的线程,若线程添加失败,则证明线程数也也满,则执行绝策略
else if (!addWorker(command, false))
reject(command);
}
java
// 执行配置的饱和策略
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
整体看代码,会发现他虽然叫execute方法,但实际上他没有真正进行所谓的execute,而是根据条件判断是否需要添加新的woker。点开addWorker方法。
java
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
//获取当前的线程池状态和数量
int c = ctl.get();
//获取线程池状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (
// 线程池处于STOP,TIDYING,TERMINATED,SHUTDOWN状态时,都不能新增线程
rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//查看线程数
int wc = workerCountOf(c);
// 线程数超限制则禁止新增线程
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// cas增加线程数,成功则推出双循环
if (compareAndIncrementWorkerCount(c))
break retry;
//如果cas增加失败,则重新获取线程池状态
c = ctl.get(); // Re-read ctl
//线程池状态不一致,则到最外层循环,重新开始,一致则重新进行线程的增加
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// cas新增线程个数成功
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//正式创建线程
w = new Worker(firstTask);
// 获取Worker的thread对象
final Thread t = w.thread;
if (t != null) {
// 加锁,可能会有多个线程同时执行到这里
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
// 再次检查线程池状态
int rs = runStateOf(ctl.get());
// 线程池状态为RUNNING状态,或者线程池状态为SHUTDOWN,并且firstTask为null,则新增线程
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//判断当前线程是否已经启动
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 添加新的work线程到workers中
workers.add(w);
int s = workers.size();
//个数超出则创建失败
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 线程添加成功,则启动work线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
//如果线程启动失败,则删除work线程
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
代码有点长,甚至还有点老,现在大家应该都不会使用goto语法了,看一下提交记录,这时候感觉我小学是不是还没毕业。。。
回归正题,整体的addWorker还是很长的,所以按功能我们可以给他拆分一下。
java
retry:
for (;;) {
//获取当前的线程池状态和数量
int c = ctl.get();
//获取线程池状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (
// 线程池处于STOP,TIDYING,TERMINATED,SHUTDOWN状态时,都不能新增有任务的线程,但可以新增空的线程
rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//查看线程数
int wc = workerCountOf(c);
// 线程数超限制则禁止新增线程
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// cas增加线程数,成功则推出双循环
if (compareAndIncrementWorkerCount(c))
break retry;
//如果cas增加失败,则重新获取线程池状态
c = ctl.get(); // Re-read ctl
//线程池状态不一致,则到最外层循环,重新开始,一致则重新进行线程的增加
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
这块主要是通过自旋,去增加线程数,如果ThreadPoolExecutor处于STOP,TIDYING,TERMINATED,SHUTDOWN状态时则会拒接添加新的线程,如果ThreadPoolExecutor的状态为RUNNING,则通过cas进行线程数的增加,成功则退出循环,如果线程数没有超过最大的数却还是失败,则会重新判断当前ThreadPoolExecutor的状态和刚开始的ThreadPoolExecutor的状态是否一致,不一致则会重新最外部的自旋,否则会继续cas增加线程数。 线程数增加成功后,就进入下面这部分,也就是正式创建worker。
java
// 独占锁
private final ReentrantLock mainLock = new ReentrantLock();
/**
* woker集合
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
java
// woker启动是否失败
boolean workerStarted = false;
// woker添加是否成功
boolean workerAdded = false;
Worker w = null;
try {
//正式创建线程
w = new Worker(firstTask);
// 获取Worker的thread对象
final Thread t = w.thread;
if (t != null) {
// 加锁,可能会有多个线程同时执行到这里
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
// 再次检查线程池状态
int rs = runStateOf(ctl.get());
// 线程池状态为RUNNING状态,或者线程池状态为SHUTDOWN,并且firstTask为null,则新增线程
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//判断当前线程是否已经启动
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 添加新的work线程到workers中
workers.add(w);
int s = workers.size();
//个数超出则创建失败
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 线程添加成功,则启动work线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
//如果线程启动失败,则删除work线程
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
到这里整个worker就创建完成了,但是还有一个问题就是还是没有找到执行消费队列的方法。点开worker构造函数,你会发现,他这里创建线程时传入的runnable是自己,这就说明Worker继承了Runnable接口,那就简单了,找到run方法就行了。可以看到run方法调用了runWorker方法。
java
//woker构造函数
Worker(Runnable firstTask) {
//防止worker创建时呗中断
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
java
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
点开runworker
java
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//因为初始化worker的时候,会把当前线程的中断状态置为-1,所以要重置一下
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//如果任务不为空,或者从任务队列中获取到了任务,则执行任务
while (task != null || (task = getTask()) != null) {
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;
//统计当前work完成了多少任务数
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//清理work
processWorkerExit(w, completedAbruptly);
}
}
java
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//如果线程异常退出,则work线程数减1
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//统计整个线程池的完成的工作数
completedTaskCount += w.completedTasks;
// 删除当前的work线程,回收线程
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试设置线程池未Terminated状态
tryTerminate();
//获取当前线程池状态和数量
int c = ctl.get();
// 线程池状态为RUNNING,SHUTDOWN时,判断线程数是否小于核心线程数,小于则创建一个没有任务的work线程
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
总而言之,ThreadPoolExecutor实际就是一个生产消费者的模型,用户添加任务到线程池,相当于生产者生产元素,worker线程集合执行任务或者从任务队列获取任务,就相当于消费者消费.