关于线程池ThreadPoolExecutor的生命周期,其转换图如下。
shutdown方法
shutdown()方法源码十分简单
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
checkShutdownAccess()方法是安全权限管理相关的,onShutdown()在ThreadPoolExecutor中是一个空方法。主要需要了解的就是advanceRunState(SHUTDOWN),interruptIdleWorkers() 方法。
属性ctl是一个AtomicInteger类,它同时包含两部分的信息:线程池的运行状态 (runState) 和线程池内有效线程的数量 (workerCount),高3位保存runState,低29位保存workerCount,两个变量之间互不干扰。用一个变量去存储两个值,可避免在做相关决策时,出现不一致的情况,不必为了维护两者的一致,而占用锁资源
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
另外,从源码中看到:
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;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
各个状态在高3位分别对应:
| RUNNING | 111 |
|---|---|
| SHUTDOWN | 000 |
| STOP | 001 |
| TIDYING | 010 |
| TERMINATED | 011 |
所以advanceRunState方法主要是将ctl状态设置为"targetState",在shutdown方法中就是设为SHUTDOWN。
这里 if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) 使得只有一个线程能够成功将线程池设为targetState状态。
接下来是interruptIdleWorkers方法,如下:
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
其中interruptIdleWorkers方法如下:
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
属性worker是一个HashSet,对HashSet中的每个Worker,在worker的所在线程不是interrupted的情况下**(!t.isInterrupted())**,会去调用worker的tryLock()方法,用来判断该worker是否在工作。具体原理需要结合Worker的工作流程来解释。
如图,所示。当我们调用threadPoolExecutor.execute( Runnable runnable )方法给线程池提交任务的时候,最终会在一个另外的“工作线程”中执行runWorker方法
runWorker方法的代码如下:
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);
}
}
可以看到,源代码的注释里也写了 w.unlock(); 是为了 允许中断。那它为什么能允许中断呢?那是因为Worker类继承了AbstractQueuedSynchronizer类,Worker类的unlock方法会直接将AQS的state变量设为0,然后返回true。 所以当state为0的时候表示这个Worker的所在线程是可以被中断的。
Worker类的unlock逻辑
public void unlock() { release(1); }
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
另一方面,在Worker类的while循环中,如果Worker线程成功获取到task,那么它会首先调用Woker类的lock方法。lock方法会尝试把state从0设为1,如果成功就表示当前的Worker所在的线程正在工作。
Worker类的lock方法逻辑
public void lock() { acquire(1); }
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
所以回头看之前的interruptIdleWorkers()方法,就能明白这里:
private void interruptIdleWorkers(boolean onlyOne) {
if (!t.isInterrupted() && w.tryLock())
......
}
是怎样判断出当前的Worker线程是空闲的了
shutdownNow方法
源码如下:
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
可以看到,与shutdonw方法类似,shutdownNow方法也是先检查安全权限,然后用advanceRunState方法将状态设为STOP。
但是与shutdown方法不同的是,这里的是直接用interruptWorkers方法中断Workers工作线程,而不是像shutdown方法那样只中断那些空闲的工作线程。
interruptWorkers逻辑如下:
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
在Worker的构造方法中可以看到,一开始的state值是-1。后面的注释也有说明此时禁止被中断知道Worker工作线程跑起来。
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
那什么时候会可以被中断呢?如下:
runWorker(Worker w)方法中一开始会调用unlock方法。前面也有讲解过,unlock会调用tryRealease,在此方法中会设置state为0
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
..................
}
//tryRelease 方法设置state为0
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
由此可见interruptWorkers方法直接就会把所有启动了的工作线程Worker给中断掉。
接着,会把阻塞队列中的任务清空出来,代码比较简单:
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}