1、构造方法
请参考上篇文章:http://blog.csdn.net/ochangwen/article/details/53044733
2、源码详解
线程池能够复用线程,减少线程创建,销毁,恢复等状态切换的开销,提高程序的性能。一个线程池管理了一组工作线程,同时它还包括了一个用于放置等待执行的任务的队列。
ThreadPoolExecutor类中定义了一些与线程状态与活动线程数相关的一些变量,如下:
线程池内部有一些状态,先来了解下这些状态的机制。以下用代码注释的方式来解释其中的含义。
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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;
-
-
-
-
-
-
-
-
-
-
-
- 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;
- 各状态之间可能的转变有以下几种:
- RUNNING -> SHUTDOWN
- 调用了shutdown方法,线程池实现了finalize方法,在里面调用了shutdown方法,因此shutdown可能是在finalize中被隐式调用的
- (RUNNING or SHUTDOWN) -> STOP
- 调用了shutdownNow方法
- SHUTDOWN -> TIDYING
- 当队列和线程池均为空的时候
- STOP -> TIDYING
- 当线程池为空的时候
- TIDYING -> TERMINATED
- terminated()钩子方法调用完毕
-
-
-
-
-
- private static int runStateOf(int c) { return c & ~CAPACITY; }
-
-
-
-
-
-
- private static int workerCountOf(int c) { return c & CAPACITY; }
-
-
-
-
-
- private static int ctlOf(int rs, int wc) { return rs | wc; }
1、创建线程池并执行任务
接下来通过状态来看线程池的运行:
完成线程的创建后,
首先通过 submit 或者 execute 方法提交,实际submit 方法也是内部调用 execute方法;
submit方法的实现是在AbstractExecutorService类里,三种重载方法类似,- public Future<?> submit(Runnable task) {
- if (task == null) throw new NullPointerException();
- RunnableFuture<Void> ftask = newTaskFor(task, null);
- execute(ftask);
- return ftask;
- }
execute方法是在ThreadPoolExecutor类里实现- public void execute(Runnable command) {
- if (command == null)
- throw new NullPointerException();
-
-
- int c = ctl.get();
-
-
-
-
-
-
- if (workerCountOf(c) < corePoolSize) {
-
-
-
-
-
- if (addWorker(command, true))
- return;
-
- c = ctl.get();
- }
-
-
-
-
-
-
-
- if (isRunning(c) && workQueue.offer(command)) {
- int recheck = ctl.get();
-
-
-
-
-
- if (! isRunning(recheck) && remove(command))
- reject(command);
- else if (workerCountOf(recheck) == 0)
- addWorker(null, false);
- }
-
-
-
-
-
-
- else if (!addWorker(command, false))
- reject(command);
- }
-
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- private static int workerCountOf(int c) { return c & CAPACITY; }
- private static int ctlOf(int rs, int wc) { return rs | wc; }
- private static boolean isRunning(int c) {
- return c < SHUTDOWN;
- }
当前活动的线程小于corePoolSize了,那么等于和大于corePoolSize怎么处理呢?
1> 当前活动的线程数量 >= corePoolSize 的时候,都是优先添加到队列中,直到队列满了才会去创建新的线程,在这里第20行的if语句已经体现出来了。这里利用了&&的特性,只有当第一个条件会真时才会去判断第二个条件,第一个条件是isRunning(),判断线程池是否处于RUNNING状态,因为只有在这个状态下才会接受新任务,否则就拒绝,如果正处于RUNNING状态,那么就加入队列,如果加入失败可能就是队列已经满了,这时候直接执行第29行。
2> 在execute()方法中,当 当前活动的线程数量 < corePoolSize 时,会执行addWorker()方法,关于addWorker(),它是用来直接新建线程用的,之所以叫addWorker而不是addThread是因为在线程池中,所有的线程都用一个Worker对象包装着,来看一下这个方法:
接下来介绍上面提到的addWorker方法,方法实现如下:
那么在创建线程的时候,线程执行的是什么的呢?
我们前面提到Worker继承的其实也是Runnable,它在创建线程的时候是以自身作为任务传进先创建的线程中的,这段比较简单,我就不一一注释了,只是给出源代码给大家看吧。
在继续其他方法之前,先说下Worker这个内部类。我们看一下每次新增一个线程后这个线程都做了些什么,显然需要看看Worker的run方法:
-
-
-
-
-
-
-
-
- private final class Worker
- extends AbstractQueuedSynchronizer
- implements Runnable {
- ......
- Worker(Runnable firstTask) {
- setState(-1);
- this.firstTask = firstTask;
-
- this.thread = getThreadFactory().newThread(this);
- }
-
-
- public void run() {
- runWorker(this);
- }
- ......
- }
只是简单的调用了runWorker方法,继续看runWorker: 这个方法逻辑很简单。还记得前面提到的新增线程时指定第一个任务吗?若存在第一个任务,则先执行第一个任务,否则,从队列中拿任务,不断的执行,直到getTask返回null或执行任务出错(中断或任务本身抛出异常),就退出while循环。getTask方法后面会详细讲解。当有任务执行时(之前通过参数传入的第一个任务或从队列中获取的任务),需要做一个状态判断。也就是clearInterruptsForTaskRun方法,来看看这个方法干了什么:(这个原来的方法就是下面if里的条件)
-
-
-
-
-
- final void runWorker(ThreadPoolExecutor.Worker w) {
- Thread wt = Thread.currentThread();
- Runnable task = w.firstTask;
- w.firstTask = null;
- w.unlock();
-
-
-
- boolean completedAbruptly = true;
- try {
-
- while (task != null || (task = getTask()) != null) {
- w.lock();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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);
- }
- }
-
- private static boolean runStateAtLeast(int c, int s) {
- return c >= s;
- }
-
- protected void beforeExecute(Thread t, Runnable r) { }
-
- protected void afterExecute(Runnable r, Throwable t) { }
线程结束时,会调用processWorkerExit方法做一些清理和数据同步的工作:
- <pre name="code" class="java">
-
-
-
-
- private void processWorkerExit(ThreadPoolExecutor.Worker w, boolean completedAbruptly) {
- if (completedAbruptly)
- decrementWorkerCount();
-
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- completedTaskCount += w.completedTasks;
- workers.remove(w);
- } finally {
- mainLock.unlock();
- }
-
- tryTerminate();
-
- int c = ctl.get();
-
-
-
-
- if (runStateLessThan(c, STOP)) {
- if (!completedAbruptly) {
- int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
- if (min == 0 && ! workQueue.isEmpty())
- min = 1;
-
-
-
-
- if (workerCountOf(c) >= min)
- return;
- }
-
- addWorker(null, false);
- }
- }
-
- private void decrementWorkerCount() {
- do {} while (! compareAndDecrementWorkerCount(ctl.get()));
- }
- private boolean compareAndDecrementWorkerCount(int expect) {
- return ctl.compareAndSet(expect, expect - 1);
- }
-
- private static boolean runStateLessThan(int c, int s) {
- return c < s;
- }
如果线程是异常结束(被中断、任务执行本身异常等),当前活动的线程数减少一个。如果是正常结束的呢?不应该将其也减一吗?不用担心,在runWorker的while最后一次循环中的getTask方法里做掉了。 接下来将该线程执行过的任务数加到completedTaskCount中,这个在前面也提到了。然后从workers中去除该工作线程。如果该线程的中断是因为调用了shutdown、shutdownNow接口而中断的该如何处理?就是这个tryTerminate了,来看下tryTerminate干了什么:- <pre name="code" class="java">
-
-
- final void tryTerminate() {
- for (;;) {
- int c = ctl.get();
-
-
-
-
-
-
-
-
- if (isRunning(c) ||
- runStateAtLeast(c, TIDYING) ||
- (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
- return;
-
-
- if (workerCountOf(c) != 0) {
-
-
-
-
-
-
-
-
-
-
- interruptIdleWorkers(ONLY_ONE);
- return;
- }
-
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
-
-
-
-
-
- if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
- try {
- terminated();
- } finally {
- ctl.set(ctlOf(TERMINATED, 0));
-
-
-
-
-
- termination.signalAll();
- }
- return;
- }
- } finally {
- mainLock.unlock();
- }
-
- }
- }
-
- private static boolean runStateAtLeast(int c, int s) {
- return c >= s;
- }
继续说processWorkerExit方法中调用tryTerminate之后的代码。如果池的状态仍为RUNNING,而线程是因为执行的任务本身抛出了异常而结束或正常结束时该如何处理?这时候池的状态还是RUNNING呢!那就是接下来的这个if块要做的事儿了。当池的状态还是RUNNING,又要分两种情况,一种是异常结束,一种是正常结束。异常结束比较好弄,直接加个线程替换死掉的线程就好了,也就是最后的addWorker操作。而正常结束又有几种情况了,如果允许core线程超时,也就是allowCoreThreadTimeOut为true,那么在池中没有任务的时候,调用带有时限参数的poll方法时就可能返回null,致使线程正常退出,如果允许core线程超时,池中最小的线程数可为0,如果此时队列又有任务了,那么池中必须要有一个线程,若池中活动的线程数不为0,就不需要新增线程来替换死掉的线程,否则就要新增一个;如果不允许core线程超时,池中的线程必须达到corePoolSize个才能让多的线程退出,而不需要用新的线程替换,否则也需要新增一个线程替换这个死掉的线程。
在runWorker执行任务之前调用了w.lock操作,为什么要在执行任务的时候锁定这个每个线程都有一份的锁呢?原因在于调用了线程池shutdown后(前面说过,SHUTDOWN的含义:不再接受新任务,但仍可以执行队列中的任务),会调用interruptIdleWorkers方法去终止空闲线程,该方法会持有mainLock锁,但此时队列中可能还有很多任务,线程也可能还正在执行任务,就可能有一些线程终止不掉。此时,有些线程可能刚执行任务结束,正准备再去队列中拿任务,有些可能还正在执行任务,有些可能刚拿到一个新的任务,对于仍进入队列中拿任务的线程,最终队列中任务会被拿完,而此时拿任务的线程会发现线程池的状态为SHUTDOWN,就会立马返回一个null,返回null意味着ThreadPoolExecutor.runWorker中的循环退出了,这个线程也就自动终止了;此外拿任务并没有持有mainLock锁,所以在终止空闲线程与线程非执行任务期间(如从队列获取任务)存在竞态条件。有可能已经判断了线程池的状态仍未RUNNING,准备从queue里take任务,而在执行take之前,另一个非池中的线程可能调用了shutdown,并且执行完了interruptIdleWorkers方法(马上就会介绍这个方法),若此时队列中恰好没有任务了,若这个正要调用take的线程阻塞,就不会醒过来了,不用担心,interruptIdleWorkers已经中断了该线程,而take是可以响应中断的,再调用take后会立马抛出异常。 对于正在执行中的任务,其它线程不能直接将这个正在线程中断掉,因此除了mainLock锁,interruptIdleWorkers还需要持有线程执行任务时获取的那把锁(这也是为什么执行任务的时候需要获取那个每个线程都有的锁的原因),如果获取不成功表示线程正在执行任务。
-----------------------------------------------------------------------------------------
2、关闭线程池
看下终止空闲线程的方法实现:
- private void interruptIdleWorkers() {
- interruptIdleWorkers(false);
- }
-
- private void interruptIdleWorkers(boolean onlyOne) {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (ThreadPoolExecutor.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();
- }
- }
- private void interruptWorkers() {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (ThreadPoolExecutor.Worker w : workers)
- w.interruptIfStarted();
- } finally {
- mainLock.unlock();
- }
- }
interruptIdleWorkers遍历workers中所有的工作线程,若线程没有被中断且能立即(tryLock)获取到前面提到的那把线程任务锁时,就中断该线程。为什么需要持有mainLock?mainLock是用来保护workers变量的。
shutdown是持有mainLock的,但是runWorker的时候并没有,那么,会不会出现碰巧出现同一时刻池中所有线程都刚好执行完任务,去取任务的时候发现池的状态为SHUTDOWN,就立即返回null并终止线程,而导致队列中的剩下的任务得不到执行?这是不会出现的,来看下getTask的实现:
- private Runnable getTask() {
- boolean timedOut = false;
-
- retry:
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
-
-
- if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
- decrementWorkerCount();
- return null;
- }
-
- boolean timed;
-
- for (;;) {
- int wc = workerCountOf(c);
- timed = allowCoreThreadTimeOut || wc > corePoolSize;
-
- if (wc <= maximumPoolSize && ! (timedOut && timed))
- break;
- if (compareAndDecrementWorkerCount(c))
- return null;
- c = ctl.get();
- if (runStateOf(c) != rs)
- continue retry;
-
- }
-
- try {
- Runnable r = timed ?
- workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
- workQueue.take();
- if (r != null)
- return r;
- timedOut = true;
- } catch (InterruptedException retry) {
- timedOut = false;
- }
- }
- }
若进入这个方法的工作线程是即将要终止的线程,该方法就必须返回null,有以下几种情形需要返回null:
1、当前活动线程数超过maximumPoolSize个(调用了setMaximumPoolSize的缘故);
2、线程池已经停止(STOP);
3、线程池已经关闭(SHUTDOWN)且任务队列为空;
4、工作线程获取任务超时,且满足(allowCoreThreadTimeOut || workerCount > corePoolSize)条件
先获取线程池的状态,如果状态大于等于STOP,也就是STOP、TIDYING、TERMINATED之一,这时候不管队列中有没有任务,都不用去执行了;如果线程池的状态为SHUTDOWN且队列中没有任务了,也不用继续执行了;所以这两种场景中获取任务的线程没必要存在了,这里调用了decrementWorkerCount减少活动线程数。前面在processWorkerExit中也提到,如果任务是非正常终止,processWorkerExit里要将活动线程数减一,正常的线程退出,减一是在这里做的。返回null之后,runWorker的while循环就退出了。接下来是个嵌套循环,它的目的就是上述的1和4.后面是从队列中取任务,比较简单,不多说。
以上,核心方法分析结束。欢迎指出理解错漏的地方。
转自:http://blog.csdn.net/ochangwen/article/details/53045979