上一篇是 线程池原理分析,只是说明了其大概流程框架,这篇文章将对Java线程池的实现源码做一些分析。
Executor:执行者接口,用来执行任务,准确的说,Executor提供了executor()接口来执行已经提交的Runnable任务对象。Executor存在的目的是提供一种将任务提交和任务如何运行分开的机制。Executor接口只包括一个函数接口:void executor(Runnable command);
ThreadPoolExecutor:继承自AbstractExecutorService类的具体实现类,具体实现了线程池的功能。
ScheduleExecutorService:是一个具有延时和周期执行功能的ExecutorService,其具体实现类就是SchedulePoolExecutor。
Executors:这是一个静态工厂类,通过静态工厂方法返回一些参数默认的ThreadPoolExecutor和SchedulePoolExecutor对象。
其他都是一些抽象类和接口,就不做说明,毕竟Javaer,都懂。
综上所述:
所有的线程池实现都是基于Executor接口的,ThreadPoolExecutor是一个jdk自己实现的线程池,Executors相当于一个工具类,我们可以方便的从其中直接使用jdk实现的默认参数的ThreadPoolExecutor(但是不推荐直接使用这个工具类)
根据前面的继承关系结构图,我们知道ThreadPoolExecutor
类是JDK中实现的线程池类,根据上篇文章我们也知道,目前我们实际使用到的线程池,也是这个类的实例。
可以看到都是volatile类型的值,这里是为了配合cas操作来做到线程同步。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 这里需要特别说明变量clt,这是一个巧妙设计的状态码,可以根据位运算来获得线程池多个属性
int c = ctl.get();
// workerCount是工作线程数量
if (workerCountOf(c) < corePoolSize) { // 小于核心线程池大小
if (addWorker(command, true)) // 试图直接创建一个worker线程
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { // 提交到BlockQueue
// 这里使用offer的原因是offer不会阻塞线程,而put会阻塞线程
// 同时offer也使用了putLock保证了线程安全
// 再次确认线程池状态
int recheck = ctl.get();
// 如果线程池已经关闭,则删除任务,并且执行拒接策略
if (! isRunning(recheck) && remove(command))
reject(command);
// 如果线程池中任务数量为0,则尝试新建一个worker线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false)) // 阻塞队列满
reject(command); // 添加失败则进入拒绝策略
}
解析:executor方法是添加任务到线程池中的方法,它会分三种情况进行处理:
可以看到,整个流程和我们之前说的一模一样。只是使用了多次检查标志位,CAS操作来确保线程安全的细节,需要注意。
这个方法是线程池的入口方法,非常关键,可以说是线程池的调度器
private boolean addWorker(Runnable firstTask, boolean core) {
// 这里使用到了JUC中常用的CAS循环
retry:
for (;;) {
int c = ctl.get(); // 获取线程池信息值
int rs = runStateOf(c); // 获取线程池运行状态
// Check if queue empty only if necessary.
// rs>= SHUTDOWN都是线程池无效的情况
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c); // 获取工作线程数量
// 如果工作线程数量超过了限制,返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// CAS增加c的值,失败则退出循环
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs) // 如果线程池状态与之前不同则跳转回retry
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
} // 以上操作都是针对线程池的状态码和运行状态的操作
// 下面的操作是针对添加线程到线程池,提交(第一个)任务并且运行
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); // 新建一个Worker对象
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());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// workers是一个hashset,我们将新建的Worker对象添加
workers.add(w);
int s = workers.size();
if (s > largestPoolSize) // 线程池中曾经有的Worker对象的最大数
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); // 启动一个线程,调用worker的run方法
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
这个方法的主要作用就是添加Worker线程到线程池,当然要注意其中对于线程池状态的判断,以及对于线程安全的控制手段。
这里我们注意到,线程池实际上添加一个线程,是创建了一个Worker对象,其实这个Worker对象就是线程池中的实际工作人员。
// Worker内部类,注意这个类实现了Runnable接口,继承自AQS类
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
// thread通过工厂模式获得,这样做的好处是可以保证线程的统一
// 比如线程名字,优先级,是否为守护线程等等
// 传入了this指针,这样thread对象线程执行自己的run方法
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
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类是一个方便维护线程的类,一个Worker里包装了一个Thread,然后再由线程池同一维护一个HashSet
Worker里的核心方法是run,而run方法中的runWorker方法又是线程池处理Worker对象(或者说线程)的一个核心方法。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
// 获得传入的task对象,即提交到线程池的任务
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// getTask只有在这个任务需要被取消
//(线程池关闭,超时,线程池中线程数量超最大值)的情况下
// 才会返回null,其余情况下一律返回需要执行的task
while (task != null || (task = getTask()) != null) {
w.lock(); // 这里需要获取锁
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
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 {
// 可以看到,afterExecutr作用是获得任务运行中抛出的任何异常
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock(); // 解锁
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
这里需要注意,持续从阻塞队列中取得task的getTask()
方法:getTask()
返回null以后,就会进入finally代码块,也就是说只要getTask()
返回null,那么这个worker线程就以及完成他的使命,可以销毁了!
可以看到,这个方法是线程池中真正执行提交任务的核心方法,可以说是线程池运的发动机
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 这里需要注意的一点细节是:如果线程池预热完成
//(也就是说worker线程已经达到了coreSize以后),
// 那么以后提交的所有线程,都会先进队列,
// 然后再由getTask()方法获得到worker线程执行
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 以上,还是需要先判断线程池的状态
int wc = workerCountOf(c);
// Are workers subject to culling?
// 判断是否需要超时控制
// 依据是两个,我们下面再说这个依据
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 如果超过最大线程数,或者有超时控制,则根据需要关闭工作线程
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 从队列中获取任务
// 同时有超时控制的策略
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
这个方法也是至关重要,**我们记得,线程池的调度器–execute方法,会把任务提交到阻塞队列中,而这个方法,就是不断地从队列中取出一开始提交的任务,交给worker线程执行任务,**同时也有很多判断策略,包括线程池的关闭以及超时策略,都跟他息息相关。
PS :
超时关闭线程的策略有两种:
其余情况getTask()返回null就是线程池关闭的情况了。
最后候我们结合源码再来看一下线程池的执行流程:
addWorker()
,调用Worker.thread.start()
启动一个新的worker线程,worker线程runWorker()
正式进入循环开始干活execute()
,如果线程数大于corePoolSize,则进入阻塞Queue等待addWorker()
,直到线程达到maximumPoolSizegetTask()
,从阻塞Queue取任务,同时有超时策略take()
方法将worker线程等待,直到又有任务被添加,worker线程才被唤醒(这是阻塞队列的活了,和线程池关系不大)getTask()
会根据状态码判断一个worker线程是不是超时了,超时就返回null,这个worker线程就会自毁当然,这里我们分析的都是核心方法,线程池中还有很多其他方法,这里就不一一分析了,JUC包源码可以说是可读性最高的源码,我们更重要的是获取其中的编程智慧和架构智慧!