上一篇说到了execute的执行过程,接下来讲一讲线程创建的过程,即addWorker(Runnable firstTask, boolean core)
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 (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
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 {
w = new Worker(firstTask);
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.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;
}
addWorker两个参数,firstTask表示线程创建成功后执行firstTask,core表示创建是否是核心线程池里的线程
1.有两层死循环可以理解为自旋,外层的自旋,先获取当前的线程池状态rs,如果当前rs的状态大于等于SHUTDOWN的或者SHUTDOWN状态且队列没有任务了,创建失败,如果rs的状态为RUNNING,则进入第二层自旋
2.获取当前的线程数wc,判断wc是否大于CAPACITY,CAPACITY为5亿多基本不可能,接着再根据core的值判断wc是要大于corePoolSize还是maximumPoolSize,满足其中一个条件,就创建失败。
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
3.如果线程数符合要求就会通过CAS的方式增加当前线程数量的值,如果CAS成功则跳出两层自旋
if (compareAndIncrementWorkerCount(c))
break retry;
,如果失败,再次判断下当前的状态是否跟之前的rs一致,如果不一致回到最外层的循环,重新走1步骤,如果一致,则重新走2步骤
if (runStateOf(c) != rs)
continue retry;
4.线程池中的线程都被包装成工作线程Worker,线程在Worker里面创建。创建一个工作线程,把firstTask传进去
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;
this.thread = getThreadFactory().newThread(this);
}
}
拿到Worker里的线程
final Thread t = w.thread;
如果t不为空,就会获取锁,获取是为了一些操作能够安全的更新如工作集合的添加和largestPoolSize的修改,获取到锁后,获取当前线程池的状态rs,判断rs是否符合状态,符合的话再判断t是否已经启动,如果启动抛出异常,否则把该工作线程添加到工作线程的集合中,并修改largestPoolSize,紧接着释放锁。然后启动线程
if (workerAdded) {
t.start();
workerStarted = true;
}
如果线程启动失败,则会把刚刚的工作线程从工作线程集合中删除,并把线程数量减一
finally {
if (! workerStarted)
addWorkerFailed(w);
}
----------
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
上面用的finally的原因是因为在之前的两层循环中,已经把线程数量加一了,所以无论如何只要线程没启动成功就得要把线程数量减一,以确保数量正确。
讲完了如何添加工作线程的,现在来讲一讲工作线程是如何运行起来的。工作线程中的运行是执行runWorker()
public void run() {
runWorker(this);
}
----------------------------------
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
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 {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
线程执行前先解锁,确保能够被中断,接着使用while一直循环从getTask()获取任务,获取到任务后,先把线程上锁,然后判断当前线程的状态是否是STOP,如果是STOP,则中断当前的线程。在运行真正的线程run时前有一个beforeExecute,运行完后有一个afterExecute,这两个方法都是空方法,留着给开发人员实现,可以对线程的运行前面做一下操作,当线程运行完后,当前工作线程的完成任务数加一,同时线程释放锁
finally {
task = null;
w.completedTasks++;
w.unlock();
}
如果获取不到任务,则回收工作线程
finally {
processWorkerExit(w, completedAbruptly);
}
现在我们来看看,工作线程是如何获取到任务,即getTask() 方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
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;
}
}
}
1.设置一个变量timeOut来判断上一次获取任务是否超时,
2.接着获取当前的线程池状态rs,判断当前线程池状态是否为STOP或者是SHUTDOWN且队列为空,如果是减少线程数量-1,返回null。
3.否则获取当前的线程数量wc,同时设置一个变量timed判断是否核心线程允许超时,紧接着判断 wc 是否大于 maximumPoolSize ,或者上一次获取任务超时且队列为空,符合就减少线程数量,返回null
4.最重要的一步
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
根据timed来判断是阻塞的获取任务一直等待直到有任务,还是根据keepAliveTime等待一定时间如果没有获取到任务就返回null,如果获取到任务就返回任务,获取不到任务任务就把timedOut 置为true进行下一次的循环,同时如果阻塞线程被中断了,这里会捕获到,把timedOut = false进行下一次的循环。
在这里额外介绍两点
1.为什么要判断wc > maximumPoolSize,这是因为有可能使用了 setMaximumPoolSize 把 maximumPoolSize调小了,导致目前的线程数量超过最大值,所以要把超出的部分减去同时回收超过的部分
2.timed = allowCoreThreadTimeOut || wc > corePoolSize;,在线程池中使用 allowCoreThreadTimeOut 来控制核心线程池的线程是否也应该被超时回收,如果为true则核心线程池也需要,为false则超过核心线程池数量的线程才会被超时回收