Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析(转载)

Java中使用线程池技术一般都是使用Executors这个工厂类,它提供了非常简单方法来创建各种类型的线程池:

1.public static ExecutorService newFixedThreadPool(int nThreads)
2.public static ExecutorService newSingleThreadExecutor()
3.public static ExecutorService newCachedThreadPool()
4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

thread-pool-executor-overview.png

核心的接口其实是Executor,它只有一个execute方法抽象为对任务(Runnable接口)的执行, ExecutorService接口在Executor的基础上提供了对任务执行的生命周期的管理,主要是submitshutdown方法, AbstractExecutorServiceExecutorService一些方法做了默认的实现,主要是submit和invoke方法,而真正的任务执行 的Executor接口execute方法是由子类实现,就是ThreadPoolExecutor,它实现了基于线程池的任务执行框架,所以要了解 JDK的线程池,那么就得先看这个类。

再看execute方法之前需要先介几个变量或类。

ctl

1.private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

这个变量是整个类的核心,AtomicInteger保证了对这个变量的操作是原子的,通过巧妙的操作,ThreadPoolExecutor用这一个变量保存了两个内容:

所有有效线程的数量 各个线程的状态(runState)

低29位存线程数,高3位存runState,这样runState有5个值:

RUNNING:-536870912 SHUTDOWN:0 STOP:536870912 TIDYING:1073741824 TERMINATED:1610612736

线程池中各个状态间的转换比较复杂,主要记住下面内容就可以了:

RUNNING状态:线程池正常运行,可以接受新的任务并处理队列中的任务; SHUTDOWN状态:不再接受新的任务,但是会执行队列中的任务; STOP状态:不再接受新任务,不处理队列中的任务

围绕ctl变量有一些操作,了解这些方法是看懂后面一些晦涩代码的基础:

加载中...加载中...

01./**
02.* 这个方法用于取出runState的值 因为CAPACITY值为:00011111111111111111111111111111
03.* ~为按位取反操作,则~CAPACITY值为:11100000000000000000000000000000
04.* 再同参数做&操作,就将低29位置0了,而高3位还是保持原先的值,也就是runState的值
05.*
06.* @param c
07.*            该参数为存储runState和workerCount的int值
08.* @return runState的值
09.*/
10.private static int runStateOf(int c) {
11.return c & ~CAPACITY;
12.}
13. 
14. 
15./**
16.* 这个方法用于取出workerCount的值
17.* 因为CAPACITY值为:00011111111111111111111111111111,所以&操作将参数的高3位置0了
18.* 保留参数的低29位,也就是workerCount的值
19.*
20.* @param c
21.*            ctl, 存储runState和workerCount的int值
22.* @return workerCount的值
23.*/
24.private static int workerCountOf(int c) {
25.return c & CAPACITY;
26.}
27. 
28./**
29.* 将runState和workerCount存到同一个int中
30.* “|”运算的意思是,假设rs的值是101000,wc的值是000111,则他们位或运算的值为101111
31.*
32.* @param rs
33.*            runState移位过后的值,负责填充返回值的高3位
34.* @param wc
35.*            workerCount移位过后的值,负责填充返回值的低29位
36.* @return 两者或运算过后的值
37.*/
38.private static int ctlOf(int rs, int wc) {
39.return rs | wc;
40.}
41. 
42.// 只有RUNNING状态会小于0
43.private static boolean isRunning(int c) {
44.return c < SHUTDOWN;
45.}

 

corePoolSize

核心线程池大小,活动线程小于corePoolSize则直接创建,大于等于则先加到workQueue中,队列满了才创建新的线程。

 

keepAliveTime

线程从队列中获取任务的超时时间,也就是说如果线程空闲超过这个时间就会终止。

 

Worker

1.private final class Worker extends AbstractQueuedSynchronizer implements Runnable ...

内部类Worker是对任务的封装,所有submit的Runnable都被封装成了Worker,它本身也是一个Runnable, 然后利用AQS框架(关于AQS可以看我这篇文章)实现了一个简单的非重入的互斥锁, 实现互斥锁主要目的是为了中断的时候判断线程是在空闲还是运行,可以看后面shutdownshutdownNow方法的分析。

01.// state只有0和1,互斥
02.protected boolean tryAcquire(int unused) {
03.if (compareAndSetState(01)) {
04.setExclusiveOwnerThread(Thread.currentThread());
05.return true;// 成功获得锁
06.}
07.// 线程进入等待队列
08.return false;
09.}
10. 
11.protected boolean tryRelease(int unused) {
12.setExclusiveOwnerThread(null);
13.setState(0);
14.return true;
15.}

之所以不用ReentrantLock是为了避免任务执行的代码中修改线程池的变量,如setCorePoolSize,因为ReentrantLock是可重入的。

 

execute

execute方法主要三个步骤:

活动线程小于corePoolSize的时候创建新的线程; 活动线程大于corePoolSize时都是先加入到任务队列当中; 任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。

01.public void execute(Runnable command) {
02.if (command == null)
03.throw new NullPointerException();
04. 
05.int c = ctl.get();
06.// 活动线程数 < corePoolSize
07.if (workerCountOf(c) < corePoolSize) {
08.// 直接启动新的线程。第二个参数true:addWorker中会重新检查workerCount是否小于corePoolSize
09.if (addWorker(command, true))
10.// 添加成功返回
11.return;
12.c = ctl.get();
13.}
14.// 活动线程数 >= corePoolSize
15.// runState为RUNNING && 队列未满
16.if (isRunning(c) && workQueue.offer(command)) {
17.int recheck = ctl.get();
18.// double check
19.// 非RUNNING状态 则从workQueue中移除任务并拒绝
20.if (!isRunning(recheck) && remove(command))
21.reject(command);// 采用线程池指定的策略拒绝任务
22.// 线程池处于RUNNING状态 || 线程池处于非RUNNING状态但是任务移除失败
23.else if (workerCountOf(recheck) == 0)
24.// 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。
25.// 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务
26.addWorker(nullfalse);
27. 
28.// 两种情况:
29.// 1.非RUNNING状态拒绝新的任务
30.// 2.队列满了启动新的线程失败(workCount > maximumPoolSize)
31.else if (!addWorker(command, false))
32.reject(command);
33.}

注释比较清楚了就不再解释了,其中比较难理解的应该是addWorker(null, false);这一行,这要结合addWorker一起来看。 主要目的是防止HUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。

 

addWorker

这个方法理解起来比较费劲。

加载中...加载中...

01.private boolean addWorker(Runnable firstTask, boolean core) {
02.retry: for (;;) {
03.int c = ctl.get();
04.int rs = runStateOf(c);// 当前线程池状态
05. 
06.// Check if queue empty only if necessary.
07.// 这条语句等价:rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null ||
08.// workQueue.isEmpty())
09.// 满足下列调价则直接返回false,线程创建失败:
10.// rs > SHUTDOWN:STOP || TIDYING || TERMINATED 此时不再接受新的任务,且所有任务执行结束
11.// rs = SHUTDOWN:firtTask != null 此时不再接受任务,但是仍然会执行队列中的任务
12.// rs = SHUTDOWN:firtTask == null见execute方法的addWorker(null,
13.// false),任务为null && 队列为空
14.// 最后一种情况也就是说SHUTDONW状态下,如果队列不为空还得接着往下执行,为什么?add一个null任务目的到底是什么?
15.// 看execute方法只有workCount==0的时候firstTask才会为null结合这里的条件就是线程池SHUTDOWN了不再接受新任务
16.// 但是此时队列不为空,那么还得创建线程把任务给执行完才行。
17.if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
18.return false;
19. 
20.// 走到这的情形:
21.// 1.线程池状态为RUNNING
22.// 2.SHUTDOWN状态,但队列中还有任务需要执行
23.for (;;) {
24.int wc = workerCountOf(c);
25.if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
26.return false;
27.if (compareAndIncrementWorkerCount(c))// 原子操作递增workCount
28.break retry;// 操作成功跳出的重试的循环
29.c = ctl.get(); // Re-read ctl
30.if (runStateOf(c) != rs)// 如果线程池的状态发生变化则重试
31.continue retry;
32.// else CAS failed due to workerCount change; retry inner loop
33.}
34.}
35. 
36.// wokerCount递增成功
37. 
38.boolean workerStarted = false;
39.boolean workerAdded = false;
40.Worker w = null;
41.try {
42.final ReentrantLock mainLock = this.mainLock;
43.w = new Worker(firstTask);
44.final Thread t = w.thread;
45.if (t != null) {
46.// 并发的访问线程池workers对象必须加锁
47.mainLock.lock();
48.try {
49.// Recheck while holding lock.
50.// Back out on ThreadFactory failure or if
51.// shut down before lock acquired.
52.int c = ctl.get();
53.int rs = runStateOf(c);
54. 
55.// RUNNING状态 || SHUTDONW状态下清理队列中剩余的任务
56.if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
57.if (t.isAlive()) // precheck that t is startable
58.throw new IllegalThreadStateException();
59.// 将新启动的线程添加到线程池中
60.workers.add(w);
61.// 更新largestPoolSize
62.int s = workers.size();
63.if (s > largestPoolSize)
64.largestPoolSize = s;
65.workerAdded = true;
66.}
67.finally {
68.mainLock.unlock();
69.}
70.// 启动新添加的线程,这个线程首先执行firstTask,然后不停的从队列中取任务执行
71.// 当等待keepAlieTime还没有任务执行则该线程结束。见runWoker和getTask方法的代码。
72.if (workerAdded) {
73.t.start();// 最终执行的是ThreadPoolExecutor的runWoker方法
74.workerStarted = true;
75.}
76.}
77.finally {
78.// 线程启动失败,则从wokers中移除w并递减wokerCount
79.if (!workerStarted)
80.// 递减wokerCount会触发tryTerminate方法
81.addWorkerFailed(w);
82.}
83.return workerStarted;
84.}

 

runWorker

任务添加成功后实际执行的是runWorker这个方法,这个方法非常重要,简单来说它做的就是:

第一次启动会执行初始化传进来的任务firstTask; 然后会从workQueue中取任务执行,如果队列为空则等待keepAliveTime这么长时间。 加载中...加载中...

01.final void runWorker(Worker w) {
02.Thread wt = Thread.currentThread();
03.Runnable task = w.firstTask;
04.w.firstTask = null;
05.// Worker的构造函数中抑制了线程中断setState(-1),所以这里需要unlock从而允许中断
06.w.unlock();
07.// 用于标识是否异常终止,finally中processWorkerExit的方法会有不同逻辑
08.// 为true的情况:1.执行任务抛出异常;2.被中断。
09.boolean completedAbruptly = true;
10.try {
11.// 如果getTask返回null那么getTask中会将workerCount递减,如果异常了这个递减操作会在processWorkerExit中处理
12.while (task != null || (task = getTask()) != null) {
13.w.lock();
14.// If pool is stopping, ensure thread is interrupted;
15.// if not, ensure thread is not interrupted. This
16.// requires a recheck in second case to deal with
17.// shutdownNow race while clearing interrupt
18.if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
19.&& !wt.isInterrupted())
20.wt.interrupt();
21.try {
22.// 任务执行前可以插入一些处理,子类重载该方法
23.beforeExecute(wt, task);
24.Throwable thrown = null;
25.try {
26.task.run();// 执行用户任务
27.catch (RuntimeException x) {
28.thrown = x;
29.throw x;
30.catch (Error x) {
31.thrown = x;
32.throw x;
33.catch (Throwable x) {
34.thrown = x;
35.throw new Error(x);
36.finally {
37.// 和beforeExecute一样,留给子类去重载
38.afterExecute(task, thrown);
39.}
40.finally {
41.task = null;
42.w.completedTasks++;
43.w.unlock();
44.}
45.}
46. 
47.completedAbruptly = false;
48.finally {
49.// 结束线程的一些清理工作
50.processWorkerExit(w, completedAbruptly);
51.}
52.}

 

getTask

加载中...加载中...

01.private Runnable getTask() {
02.boolean timedOut = false// Did the last poll() time out?
03. 
04.retry: for (;;) {
05.int c = ctl.get();
06.int rs = runStateOf(c);
07. 
08.// Check if queue empty only if necessary.
09.// 1.rs > SHUTDOWN 所以rs至少等于STOP,这时不再处理队列中的任务
10.// 2.rs = SHUTDOWN 所以rs>=STOP肯定不成立,这时还需要处理队列中的任务除非队列为空
11.// 这两种情况都会返回null让runWoker退出while循环也就是当前线程结束了,所以必须要decrement
12.// wokerCount
13.if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
14.// 递减workerCount值
15.decrementWorkerCount();
16.return null;
17.}
18. 
19.// 标记从队列中取任务时是否设置超时时间
20.boolean timed; // Are workers subject to culling?
21. 
22.// 1.RUNING状态
23.// 2.SHUTDOWN状态,但队列中还有任务需要执行
24.for (;;) {
25.int wc = workerCountOf(c);
26. 
27.// 1.core thread允许被超时,那么超过corePoolSize的的线程必定有超时
28.// 2.allowCoreThreadTimeOut == false && wc >
29.// corePoolSize时,一般都是这种情况,core thread即使空闲也不会被回收,只要超过的线程才会
30.timed = allowCoreThreadTimeOut || wc > corePoolSize;
31. 
32.// 从addWorker可以看到一般wc不会大于maximumPoolSize,所以更关心后面半句的情形:
33.// 1. timedOut == false 第一次执行循环, 从队列中取出任务不为null方法返回 或者
34.// poll出异常了重试
35.// 2.timeOut == true && timed ==
36.// false:看后面的代码workerQueue.poll超时时timeOut才为true,
37.// 并且timed要为false,这两个条件相悖不可能同时成立(既然有超时那么timed肯定为true)
38.// 所以超时不会继续执行而是return null结束线程。(重点:线程是如何超时的???)
39.if (wc <= maximumPoolSize && !(timedOut && timed))
40.break;
41. 
42.// workerCount递减,结束当前thread
43.if (compareAndDecrementWorkerCount(c))
44.return null;
45.c = ctl.get(); // Re-read ctl
46.// 需要重新检查线程池状态,因为上述操作过程中线程池可能被SHUTDOWN
47.if (runStateOf(c) != rs)
48.continue retry;
49.// else CAS failed due to workerCount change; retry inner loop
50.}
51. 
52.try {
53.// 1.以指定的超时时间从队列中取任务
54.// 2.core thread没有超时
55.Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
56.if (r != null)
57.return r;
58.timedOut = true;// 超时
59.catch (InterruptedException retry) {
60.timedOut = false;// 线程被中断重试
61.}
62.}
63.}

 

processWorkerExit

线程退出会执行这个方法做一些清理工作。

加载中...加载中...

01.private void processWorkerExit(Worker w, boolean completedAbruptly) {
02.// 正常的话再runWorker的getTask方法workerCount已经被减一了
03.if (completedAbruptly)
04.decrementWorkerCount();
05. 
06.final ReentrantLock mainLock = this.mainLock;
07.mainLock.lock();
08.try {
09.// 累加线程的completedTasks
10.completedTaskCount += w.completedTasks;
11.// 从线程池中移除超时或者出现异常的线程
12.workers.remove(w);
13.finally {
14.mainLock.unlock();
15.}
16. 
17.// 尝试停止线程池
18.tryTerminate();
19. 
20.int c = ctl.get();
21.// runState为RUNNING或SHUTDOWN
22.if (runStateLessThan(c, STOP)) {
23.// 线程不是异常结束
24.if (!completedAbruptly) {
25.// 线程池最小空闲数,允许core thread超时就是0,否则就是corePoolSize
26.int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
27.// 如果min == 0但是队列不为空要保证有1个线程来执行队列中的任务
28.if (min == 0 && !workQueue.isEmpty())
29.min = 1;
30.// 线程池还不为空那就不用担心了
31.if (workerCountOf(c) >= min)
32.return// replacement not needed
33.}
34.// 1.线程异常退出
35.// 2.线程池为空,但是队列中还有任务没执行,看addWoker方法对这种情况的处理
36.addWorker(nullfalse);
37.}
38.}

 

tryTerminate

processWorkerExit方法中会尝试调用tryTerminate来终止线程池。这个方法在任何可能导致线程池终止的动作后执行:比如减少wokerCount或SHUTDOWN状态下从队列中移除任务。

加载中...加载中...

01.final void tryTerminate() {
02.for (;;) {
03.int c = ctl.get();
04.// 以下状态直接返回:
05.// 1.线程池还处于RUNNING状态
06.// 2.SHUTDOWN状态但是任务队列非空
07.// 3.runState >= TIDYING 线程池已经停止了或在停止了
08.if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))
09.return;
10. 
11.// 只能是以下情形会继续下面的逻辑:结束线程池。
12.// 1.SHUTDOWN状态,这时不再接受新任务而且任务队列也空了
13.// 2.STOP状态,当调用了shutdownNow方法
14. 
15.// workerCount不为0则还不能停止线程池,而且这时线程都处于空闲等待的状态
16.// 需要中断让线程“醒”过来,醒过来的线程才能继续处理shutdown的信号。
17.if (workerCountOf(c) != 0) { // Eligible to terminate
18.// runWoker方法中w.unlock就是为了可以被中断,getTask方法也处理了中断。
19.// ONLY_ONE:这里只需要中断1个线程去处理shutdown信号就可以了。
20.interruptIdleWorkers(ONLY_ONE);
21.return;
22.}
23. 
24.final ReentrantLock mainLock = this.mainLock;
25.mainLock.lock();
26.try {
27.// 进入TIDYING状态
28.if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
29.try {
30.// 子类重载:一些资源清理工作
31.terminated();
32.finally {
33.// TERMINATED状态
34.ctl.set(ctlOf(TERMINATED, 0));
35.// 继续awaitTermination
36.termination.signalAll();
37.}
38.return;
39.}
40.finally {
41.mainLock.unlock();
42.}
43.// else retry on failed CAS
44.}
45.}

 

shutdown和shutdownNow

shutdown这个方法会将runState置为SHUTDOWN,会终止所有空闲的线程。

01.public void shutdown() {
02.final ReentrantLock mainLock = this.mainLock;
03.mainLock.lock();
04.try {
05.checkShutdownAccess();
06.// 线程池状态设为SHUTDOWN,如果已经至少是这个状态那么则直接返回
07.advanceRunState(SHUTDOWN);
08.// 注意这里是中断所有空闲的线程:runWorker中等待的线程被中断 → 进入processWorkerExit →
09.// tryTerminate方法中会保证队列中剩余的任务得到执行。
10.interruptIdleWorkers();
11.onShutdown(); // hook for ScheduledThreadPoolExecutor
12.finally {
13.mainLock.unlock();
14.}
15.tryTerminate();
16.}

shutdownNow方法将runState置为STOP。和shutdown方法的区别,这个方法会终止所有的线程。

01.public List<Runnable> shutdownNow() {
02.List<Runnable> tasks;
03.final ReentrantLock mainLock = this.mainLock;
04.mainLock.lock();
05.try {
06.checkShutdownAccess();
07.// STOP状态:不再接受新任务且不再执行队列中的任务。
08.advanceRunState(STOP);
09.// 中断所有线程
10.interruptWorkers();
11.// 返回队列中还没有被执行的任务。
12.tasks = drainQueue();
13.}
14.finally {
15.mainLock.unlock();
16.}
17.tryTerminate();
18.return tasks;
19.}

主要区别在于shutdown调用的是interruptIdleWorkers这个方法,而shutdownNow实际调用的是Worker类的interruptIfStarted方法:

01.private void interruptIdleWorkers(boolean onlyOne) {
02.final ReentrantLock mainLock = this.mainLock;
03.mainLock.lock();
04.try {
05.for (Worker w : workers) {
06.Thread t = w.thread;
07.// w.tryLock能获取到锁,说明该线程没有在运行,因为runWorker中执行任务会先lock,
08.// 因此保证了中断的肯定是空闲的线程。
09.if (!t.isInterrupted() && w.tryLock()) {
10.try {
11.t.interrupt();
12.catch (SecurityException ignore) {
13.finally {
14.w.unlock();
15.}
16.}
17.if (onlyOne)
18.break;
19.}
20.}
21.finally {
22.mainLock.unlock();
23.}
24.}
01.void interruptIfStarted() {
02.Thread t;
03.// 初始化时state == -1
04.if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
05.try {
06.t.interrupt();
07.catch (SecurityException ignore) {
08.}
09.}
10.}

这就是前面提到的Woker类实现AQS的主要作用。

1.<code>注意:shutdown方法可能会在finalize被隐式的调用。</code>

这篇博客基本都是代码跟注释,所以如果不是分析ThreadPoolExecutor源码的话看起来会非常无聊。

posted @ 2016-04-01 09:49  青青子衿J  阅读(140)  评论(0)    收藏  举报