一、ThreadPoolExcute类主要变量
shutdownPerm:权限检查使用
runState:运行状态,对应有RUNNING 0、SHUTDOWN 1、STOP 2、TERMINATED 3
BlockingQueue<Runnable> workQueue :任务队列
ReentrantLock mainLock:可重入锁
Condition termination=mainLock.newCondition() : 可重入锁变更条件
HashSet<Worker> workers:Runnable封装类,执行线程的池
volatile long keepAliveTime:线程存活时间
volatile boolean allowCoreThreadTimeOut:线程失败或者终止后能否使用keepAliveTime时间等待
volatile int corePoolSize;核心线程数量
volatile int maximumPoolSize;最大线程数量
volatile int poolSize;当前的线程数量
volatile RejectedExecutionHandler handler;拒绝执行Runnable后的处理器
volatile ThreadFactory threadFactory;线程工厂
RejectedExecutionHandler defaultHandler = new AbortPolicy();默认的失败处理策略
二、workQueue 和workers
1、workQueue 任务队列
①workQueue缓存没有被立即执行的Runnable,当新加入的任务大于corePoolSize又小于maximumPoolSize时,执行workQueue.offer(command),源码如下
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current <tt>RejectedExecutionHandler</tt>.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* <tt>RejectedExecutionHandler</tt>, if task cannot be accepted
* for execution
* @throws NullPointerException if command is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//如果当前线程大于核心线程或者加入works集合不成功,在这里已经执行了一次addIfUnderCorePoolSize加入works集合
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);//确保队列任务正确插入
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
②addIfUnderCorePoolSize方法,当前线程小于corePoolSize并且运行状态为running,则addThread返回Thread对象t,执行start
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
Thread t = null;
final ReentrantLock mainLock = this.mainLock;//在任务调度过程中用可重入锁mainlock进行并发控制
mainLock.lock();
try {
if (poolSize < corePoolSize && runState == RUNNING)
t = addThread(firstTask);
} finally {
mainLock.unlock();
}
if (t == null)
return false;
t.start();
return true;
}
③ensureQueuedTaskHandled方法,如果运行状态不是Running而且workQueue.remove(command)成功,转入异常处理;如果状态中stop之前且线程数小于核心线程数且workQueue队列不为空,则addThread返回Thread对象t,执行start
private void ensureQueuedTaskHandled(Runnable command) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
boolean reject = false;
Thread t = null;
try {
int state = runState;
if (state != RUNNING && workQueue.remove(command))
reject = true;
else if (state < STOP &&
poolSize < Math.max(corePoolSize, 1) &&
!workQueue.isEmpty())
t = addThread(null);
} finally {
mainLock.unlock();
}
if (reject)
reject(command);
else if (t != null)
t.start();
}
2、workers,workers是Runnable的一个封装类Worker的集合,实现了Runnable接口,workers真正的线程池核心实现,它是一个HashSet集合,保存当前正在执行和等待执行的任务。
①ReentrantLock
<span style="white-space:pre"> </span>/**
* The runLock is acquired and released surrounding each task
* execution. It mainly protects against interrupts that are
* intended to cancel the worker thread from instead
* interrupting the task being run.
*/
private final ReentrantLock runLock = new ReentrantLock();
我们看到有个runlock可重入锁定义,runlock用在中断方法interruptIfIdle以及执行任务的核心方法runtask中控制并发
②Thread thread
源码中定义了一个thread对象用来执行中断thread.interrupt()以及执行shutdown时权限检查for (Worker w : workers)security.checkAccess(w.thread);
既然Thread这么重要,那Thread对象哪里来的?我们看源码addThread方法
/**
* Creates and returns a new thread running firstTask as its first
* task. Call only while holding mainLock.
*
* @param firstTask the task the new thread should run first (or
* null if none)
* @return the new thread, or null if threadFactory fails to create thread
*/
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask);
Thread t = threadFactory.newThread(w);
if (t != null) {
w.thread = t;
workers.add(w);
int nt = ++poolSize;
if (nt > largestPoolSize)
largestPoolSize = nt;
}
return t;
}
其实这个Thread就是Worker的一个封装,一个装饰,Thread内部是一个Worker!所以他可以做到很多事情比如中断、权限检查等
③worker和workQueue 是怎么联系在一起的?我们看源码
<span style="white-space:pre"> </span>/**
* Main run loop
*/
public void run() {
try {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
runTask(task);
task = null;
}
} finally {
workerDone(this);
}
}
work执行这个run方法时候,使用getTask方法获得任务,再看getTask
Runnable getTask() {
for (;;) {
try {
int state = runState;
if (state > SHUTDOWN)
return null;
Runnable r;
if (state == SHUTDOWN) // Help drain queue
r = workQueue.poll();
else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
else
r = workQueue.take();
if (r != null)
return r;
if (workerCanExit()) {
if (runState >= SHUTDOWN) // Wake up others
interruptIdleWorkers();
return null;
}
// Else retry
} catch (InterruptedException ie) {
// On interruption, re-check runState
}
}
}
我们看到work的任务,是从workQueue中取出来的。
三、总结
我们最后整理一下思路,我们说worker是实现池的关键,为什么?
①worker中run方法定义
try {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
runTask(task);
task = null;
}
} finally {
workerDone(this);
}
关键有两个地方,while方法,只要getTask还有任务,,一直循环运行;如果没有任务了,workerDone,执行结束,然后调用workers.remove(w)把自己干掉,整个Worker就算完成任务。
②而getTask又是一个for循环,不断取任务,如果没有取到就一直循环下去,除非workerCanExit()判断,发现可以结束了,则返回null,整个过程结束。
所谓的池,就是用完后不抛弃,放回去,接着有人再用;
正是因为Work是一个执行Runnable的Runnable,而且有一个自旋锁While以及getTask里的for循环,再加上corePoolSize、poolSize、maximumPoolSize、等这些变量维持和调节池的正常大小,实现了这个线程池!
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
补充:今天再回头研究ThreadPoolExcute时,阅读runTask方法,其调用getTask时,实际调用的是接口Queue的take方法,take方法是一个阻塞方法。在此备注一下:
take: 有则返回,删除底部元素,没有则阻塞除非中断
poll:有则返回,删除底部元素,没有则返回空,不阻塞
peek:有责返回,没有则返回空,但是不删除元素
remove:有责返回,并且删除元素,没有则报错