相比1.6,1.7有些变化:

1、        添加了一个TIDYING状态。这个状态是介于STOP和TERMINATED之间的。假设运行完terminated钩子函数后状态就变成TERMINATED了;

2、        内部类Worker继承了AQS类作为一个独享锁,在执行每一个任务前会获取自己的锁。

3、        runState和poolSize两个字段被合并成一个原子字段ctl了,不再使用mainLock保护了。

一、成员变量介绍

public class ThreadPoolExecutor extends AbstractExecutorService {
/**
* ctl字段事实上表示两个含义:runState和workerCount(近似1.6中的poolSize)
* int类型。高3位表示runState,低29位表示workerCount。 眼下这个版本号也就限
* 制了线程个数不会超过2^29-1。
* RUNNING: 能接受新的任务且能处理队列里的请求
* SHUTDOWN: 不能接受新的任务可是能处理队列里的请求
* STOP: 不能接受新的任务、不能处理队列里的请求。workers会被interrupt
* TIDYING: 全部的线程都已经terminated了,正准备调用terminated()方法
* TERMININATED: terminated()方法已经调用结束了
*
* RUNNING->SHUTDOWN: 调用shutdown方法
* (RUNNING/SHUTDOWN)>STOP: 调用shutdownNow方法
* SHUTDOWN->TIDYING: 当workers和queue都空的时候
* STOP->TIDYING: 当workers为空的时候
* TIDYING->TERMINATED: 当terminated方法调用结束的时候。
* awaitTermination()直到状态为TERMINATED时才会返回。
* */
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; // 取ctl的高三位。获取runState(执行状态)
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 取ctl的低29位,获取workerCount(worker的数量)
private static int workerCountOf(int c) { return c & CAPACITY; }
// 把runState和workerCount合并成ctl,上面两个函数的反操作
private static int ctlOf(int rs, int wc) { return rs | wc; }

二、execute函数

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* 三步走:
* 1. 假设RUNNING的线程数目小于corePoolSize,直接调用addWorker方法
* 启动一个新线程。addWorker函数会检查runState和workerCount。假设不
* 须要新建一个thread就会返回false了
*
* 2. 假设任务被成功的放入了workQueue,我们仍然须要做个double-check
* 由于调用完isRunning(c)后池中的线程可能都退出了或者线程池被shut
* down了。又一次检查状态看是要remove掉新来的任务还是创建一个新线程来执
* 行(假设没有活动的线程了)
*
* 3. 假设放入workQueue失败了,我们尝试创建一个新worker。 假设失败了,
* 说明线程池被关闭了或者饱和了(超过最大值了)。就直接拒了。
*
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
// addWorker有可能会失败,失败后又一次获取状态并继续往下走
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 假设isRunning(c)&&workQueue.offer中间并发发生了shutdown,须要remove
// 掉刚放入workQueue的command任务。注意:此时假设有一个worker刚运行完一个task
// 然后从workQueue获取下一个task时,这里的remove就会失败了。
if (! isRunning(recheck) && remove(command))
reject(command);
// 假设是RUNNING状态可是没有可工作的线程。须要直接new一个
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}

execute函数大体思路和1.6一致,就三种情况:

①          当前线程池中线程数目小于corePoolSize,直接new一个thread。

②          当先线程池数据大于corePoolSize,则放入workQueue中;

③          假设workQueue满了且线程池中线程数小于maximumPoolSize,则new一个thread。

private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // 假设被shutdown了。一般就直接返回false。可是须要排除一个特例情况:当线程池状
// 态是shutdown。但workQueue不空且workers空了,会调用addWorker(null,false)
// 方法创建一个线程处理workQueue里的任务,这时不能直接返回false。
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false; for (;;) {
int wc = workerCountOf(c);
// 假设当前workers数目大于CAPACITY或者大于用户设置了。直接返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 假设不过workerCount变化了,那么继续内层的循环;假设连runState也变化了,
// 则要又一次继续外层的循环。 if (runStateOf(c) != rs)
continue retry;
}
} boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
int rs = runStateOf(c);
// 再次检查runState的状态,假设是RUNNING或者SHUTDOWN可是firstTask不空,则
// 把new出来的worker放入workers中。
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) {
// 创建worker成功后直接启动线程了
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
// 创建失败要做清理操作
addWorkerFailed(w);
}
return workerStarted;
}

addWorker函数尝试新建一个thread来执行传递给它的task。当线程池被STOP或SHUTDOWN或threadFactory返回null时或者OOM时。会返回false并做对应的清理。整个过程分为两步:1、尝试设置workerCount,成功了就到步骤2;2、尝试创建一个worker并增加到workers里。

private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}

addWorkerFailed函数做些清理操作:1、把创建的worker从workers中删除;2、把workerCount减1;3、检查能否够terminated线程池,防止这个worker的存在导致运行awaitTermination操作的client线程堵塞了。

  final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 假设是以下三种情况直接返回:
// 1.RUNNING状态; 2.runState>=TIDYING。说明有其它线程运行了tryTerminate操
// 作; 3.SHUTDOWN状态且workQueue不空
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 假设workerCount大于0。则中断一个空暇的worker,就返回了。为啥仅仅中断一个呢?
// 由于worker线程退出时也会调用tryTerminate方法(一个接一个的传播)
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
} final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 走到这里说明workers数量为0了,尝试把线程池状态改成TIDYING并调用terminated
// 函数->状态再设置成TERMINATED。 假设设置TIDYING失败,则继续循环。
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
// terminated函数抛异常也须要运行以下的操作。
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}

tryTerminate函数尝试TERMINATED线程池(当a、SHUTDOWN且queue和pool都空;b、STOP且queue为空了)。假设workers不为0,则中断随意一个空暇的worker后直接返回。否则:首先,将线程池状态改成TIDYING;其次,调用用户的钩子函数terminated;最后,将状态设置成TERMINATED。

private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
// 假设tryLock成功,就说明这个worker是空暇的。 if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
// 假设仅仅中断一个就break,仅仅有tryTerminate函数中使用到这样的情况。
break;
}
} finally {
mainLock.unlock();
}
}

interruptIdleWorkers函数依据onlyOne參数决定中断一个或全部空暇的workers(这些workers都堵塞在getTask方法中)。

三、shutdown函数

public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查调用者是否有权限运行shutdown
checkShutdownAccess();
// 将线程池的状态改成SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断全部空暇的workers
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
}

shutdown函数就运行几步:把状态改成SHUTDOWN。中断全部空暇的workers,调用onShutdown钩子函数,最后调用tryTerminate尝试终止线程池。

private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}

advanceRunState函数将线程池的状态改成指定状态值。假设如今状态值比target值大就直接返回。targeState的值是SHUTDOWN或者STOP,不能是TIDYING或者TERMINATED(这两种状态须要调用tryTerminate函数设置)。

四、shutdownNow函数

public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查调用者是否有权限运行关闭
checkShutdownAccess();
// 将线程池的状态改成STOP
advanceRunState(STOP);
// 和shutdown不同,这里中断全部的worker线程
interruptWorkers();
// 删除workQueue里的任务并返回任务列表
tasks = drainQueue();
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
return tasks;
}

shutdownNow函数会中断全部的worker线程,删除workQueue里的任务,最后尝试终止线程池并返回workQueue里的任务。

private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 中断全部的worker线程
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
List<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;
}

五、Worker内部类

private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/** 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) {
// 初始值为-1,防止worker还没启动就被interrupt了;在start開始时会将状态改成0
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
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;
}
// 參数1没有意义,是独占锁
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }

Worker类主要维护着中断的管理和其它操作(runWorker函数),继承了AQS类实现了一个不可重入的Lock。在获取到一个任务后,准备运行前首先要获取这个锁。

同一时候。在中断空暇的worker时也要先获取到这个锁。

public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
// 有时我们不想从workQueue取第一个任务,直接运行刚提交的任务
Runnable task = w.firstTask;
w.firstTask = null;
// 把state设置成0,同意中断
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 进入循环了
while (task != null || (task = getTask()) != null) {
w.lock();
// 假设是STOP状态,须要保证线程是被中断了的;
// 假设不是须要清空中断状态,可是须要又一次检查下状态防止在清除
// 中断时发生了shutdownNow
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);
}
}

runWorker函数循环从workQueue里获取task并运行,可是须要注意下面几个问题:1.假设不想从workQueue里获取第一个任务运行,那就给worker.firstTask赋值。2、假设getTask获取的值为null,或者你的task里抛异常了,那循环就退出了,然后worker线程也就退出了。3、在运行任务前先要获取worker的锁,这里防止中断正在运行的线程。4、假设你的钩子函数beforeExecute函数抛异常了,那么你的任务就不会被运行了,worker线程也会退出。5、假设task.run方法抛出Runtime或Error异常,会原样抛出。假设是Throwable,则会包装成一个Error抛出,抛出异常前会运行afterExecute钩子函数。最后线程会退出。6、假设afterExecute钩子函数抛出异常。那么worker线程也会退出。

private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out? retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // 假设SHUTDOWN且workQueue为空,或者STOP了。worker线程直接退出
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 是否要回收这个worker线程?
boolean timed; // Are workers subject to culling? for (;;) {
int wc = workerCountOf(c);
timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 假设还没有超时过(循环第一次运行到这里)直接break
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
// 否则。假设线程数大于最大限制或者已经超时过了说明这个worker线程要准备退出了
// 先设置workerCount-1,成功的话直接退出。否则,看下runState是否和rs一样,如
// 果一样就在内部循环,不一样就要到外部循环
if (compareAndDecrementWorkerCount(c))
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
} try {
// 无限堵塞或超时堵塞
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
// 没有获取到task肯定是超时了
timedOut = true;
} catch (InterruptedException retry) {
// 假设被中断了,不能算作超时
timedOut = false;
}
}
}

getTask函数是从workQueue里获取一个task,有两种策略(无限堵塞或者超时,详细要看client的配置)。

假设这个函数返回了null,那么worker线程就会退出了。退出的原因不外乎下面几种:

1.   当前线程池中worker数量大于maximumPoolSize了。

2.   线程池被STOP了(workQueue.poll/take时会捕获到InterruptedException异常);

3.   线程池被SHUTDOWN了且workQueue为空(workQueue.poll/take时会捕获到InterruptedException异常);

4.   获取task超时了(timedOut)&&(timed)。

private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 用户的函数抛异常了,须要调整workerCount的值,由于worker线程准备退出了
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount(); // 做些统计操作(bookkeeping)
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate(); int c = ctl.get();
// 假设是RUNNING或SHUTDOWN状态,要看下workQueue是否为空,
// 不能直接退出。 假设workQueue不空,至少要保留1或corePoolSize个
// 线程(看allowCoreThreadTimeOut配置)。少于这个数目,就须要通过
// addWorker(null,false)方法补充新的线程进来。 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);
}
}

processWorkerExit函数是在runWork循环退出后做的清理和bookkeeping(应该就是指completedTaskCount等变量的操作吧)操作。

completedAbruptly參数的含义是指用户的函数是否抛异常了(before/after/run等)。注意下函数最后会依据线程池的状态和配置决定是否新建一个worker线程。

Java 1.7 ThreadPoolExecutor源代码解析的更多相关文章

  1. Java 线程池(ThreadPoolExecutor)原理解析

    在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...

  2. Android Java 线程池 ThreadPoolExecutor源代码篇

    线程池简单点就是任务队列+线程组成的. 接下来我们来简单的了解下ThreadPoolExecutor的源代码. 先看ThreadPoolExecutor的简单类图,对ThreadPoolExecuto ...

  3. Java 1.7 ReentrantReadWriteLock源代码解析

    因为本人水平与表达能力有限,有错误的地方欢迎交流与指正. 1 简单介绍 可重入读写锁时基于AQS实现的,典型的用法如JDK1.7中的演示样例: class RWDictionary { private ...

  4. Java并发之ThreadPoolExecutor源码解析(二)

    ThreadPoolExecutor ThreadPoolExecutor是ExecutorService的一种实现,可以用若干已经池化的线程执行被提交的任务.使用线程池可以帮助我们限定和整合程序资源 ...

  5. 知名互联网公司校招 Java 开发岗面试知识点解析

    天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...

  6. Java开发岗面试知识点解析

    本文作者参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几个部分: Java 基础知识点 Java 常见集合 高并发编 ...

  7. [ Java面试题 ]Java 开发岗面试知识点解析

    如背景中介绍,作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向. 在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几个部分: Java 基础知识点 Jav ...

  8. Arrays.sort源代码解析

    Java Arrays.sort源代码解析 Java Arrays中提供了对所有类型的排序.其中主要分为Primitive(8种基本类型)和Object两大类. 基本类型:采用调优的快速排序: 对象类 ...

  9. Android EventBus源代码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

随机推荐

  1. SharePoint中在线编辑文档

    我一直以为只有在Document Library里面的File才会支持在线编辑.直到今天早上我才发现用IE打开List里面的Attachments也是支持在线编辑的,但前提是必须是IE浏览器. 目前正 ...

  2. Happy Java:定义泛型参数的方法

    在平时写代码时,可以自定义泛型类.当使用同一类型的对象时,这是非常有用的,但在实例化类之前,我们不知道它将是哪种类型. 下面让我们定义一个使用泛型参数的方法.首先,在定义一个类用到泛型时,必须使用特殊 ...

  3. 【转载】web网站css,js更新后客户浏览器缓存问题,需要刷新才能正常展示的解决办法

    原文:http://blog.csdn.net/csdn100861/article/details/50684438 问题描述 部署到服务器后访问发现页面展示不正常,但是刷新之后就会展示正常. 问题 ...

  4. Ubuntu 13..04 开机后桌面问题引发的一系列问题

    早上开机的时候,发现只能见到桌面,没有顶部的菜单栏,没有侧边栏(Unity桌面),不能使用快捷键(不能调出终端),貌似只能用 Ctrl Alt F1-7和关机快捷键.对于我这个刚使用Ubuntu不久的 ...

  5. 关于 f 散度

    在概率统计中,f散度是一个函数,这个函数用来衡量两个概率密度p和q的区别,也就是衡量这两个分布多么的相同或者不同. 1.f散度的定义p和q是同一个空间中的两个概率密度函数,它们之间的f散度可以用如下方 ...

  6. 【原创】纯干货,Spring-data-jpa详解,全方位介绍。(转)

    本篇进行Spring-data-jpa的介绍,几乎涵盖该框架的所有方面,在日常的开发当中,基本上能满足所有需求.这里不讲解JPA和Spring-data-jpa单独使用,所有的内容都是在和Spring ...

  7. win 7 下合并多个表格

    首先我这里从服务器上下载了一大堆的表格 分类放好之后 这里我们需要把每一类的表格合并成一张表格 这里我们使用win 7下的copy的命令 这里我的表格的格式是csv 使用cmd 我们先cd到你的表格的 ...

  8. spark-submit的参数名称解析

    执行时需要传入的参数说明 Usage: spark-submit [options] <app jar | Python file> [app options] 参数名称 含义 --mas ...

  9. 什么是内联函数(inline function)

    In C, we have used Macro function an optimized technique used by compiler to reduce the execution ti ...

  10. Atitit 如何设置与安放知识的trap陷阱  知识聚合 rss url聚合工具 以及与trap的对比

    Atitit 如何设置与安放知识的trap陷阱  知识聚合 rss url聚合工具 以及与trap的对比 1.1. 安放地点 垂直知识网站csdn cnblogs等特定频道栏目,大牛博客 1 1.2. ...