聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源码分析

ThreadPoolExecutor是Executor执行框架最重要的一个实现类,提供了线程池管理和任务管理是两个最基本的能力。这篇通过分析ThreadPoolExecutor的源码来看看如何设计和实现一个基于生产者消费者模型的执行器。

 

生产者消费者模型

生产者消费者模型包含三个角色:生产者,工作队列,消费者。对于ThreadPoolExecutor来说,

1. 生产者是任务的提交者,是外部调用ThreadPoolExecutor的线程

2. 工作队列是一个阻塞队列的接口,具体的实现类可以有很多种。BlockingQueue workQueue;

3. 消费者是封装了线程的Worker类的集合。HashSet workers = new HashSet();

 

聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源码分析_第1张图片

 

主要属性

明确了ThreadPoolExecutor的基本执行模型之后,来看下它的几个主要属性:

1. private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));    一个32位的原子整形作为线程池的状态控制描述符。低29位作为工作者线程的数量。所以工作者线程最多有2^29 -1个。高3位来保持线程池的状态。ThreadPoolExecutor总共有5种状态:

     *   RUNNING:  可以接受新任务并执行
     *   SHUTDOWN: 不再接受新任务,但是仍然执行工作队列中的任务
     *   STOP:     不再接受新任务,不执行工作队列中的任务,并且中断正在执行的任务
     *   TIDYING:  所有任务被终止,工作线程的数量为0,会去执行terminated()钩子方法
     *   TERMINATED: terminated()执行结束

 

下面是一系列ctl这个变量定义和工具方法

 

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

  2. private static final int COUNT_BITS = Integer.SIZE - 3;

  3. private static final int CAPACITY = (1 << COUNT_BITS) - 1;

  4.  
  5. // runState is stored in the high-order bits

  6. private static final int RUNNING = -1 << COUNT_BITS;

  7. private static final int SHUTDOWN = 0 << COUNT_BITS;

  8. private static final int STOP = 1 << COUNT_BITS;

  9. private static final int TIDYING = 2 << COUNT_BITS;

  10. private static final int TERMINATED = 3 << COUNT_BITS;

  11.  
  12. // Packing and unpacking ctl

  13. private static int runStateOf(int c) { return c & ~CAPACITY; }

  14. private static int workerCountOf(int c) { return c & CAPACITY; }

  15. private static int ctlOf(int rs, int wc) { return rs | wc; }

  16.  
  17. private static boolean runStateLessThan(int c, int s) {

  18. return c < s;

  19. }

  20.  
  21. private static boolean runStateAtLeast(int c, int s) {

  22. return c >= s;

  23. }

  24.  
  25. private static boolean isRunning(int c) {

  26. return c < SHUTDOWN;

  27. }

  28.  
  29. private boolean compareAndIncrementWorkerCount(int expect) {

  30. return ctl.compareAndSet(expect, expect + 1);

  31. }

  32.  
  33. private boolean compareAndDecrementWorkerCount(int expect) {

  34. return ctl.compareAndSet(expect, expect - 1);

  35. }

  36.  
  37. private void decrementWorkerCount() {

  38. do {} while (! compareAndDecrementWorkerCount(ctl.get()));

  39. }


2. private final BlockingQueue workQueue; 工作队列,采用了BlockingQueue阻塞队列的接口,具体实现类可以按照不同的策略来选择,比如有边界的ArrayBlockingQueue,无边界的LinkedBlockingQueue。

 

3. private final ReentrantLock mainLock = new ReentrantLock();  控制ThreadPoolExecutor的全局可重入锁,所有需要同步的操作都要被这个锁保护

4. private final Condition termination = mainLock.newCondition(); mainLock的条件队列,来进行wait()和notify()等条件操作

5. private final HashSet workers = new HashSet();  工作线程集合

6. private volatile ThreadFactory threadFactory; 创建线程的工厂,可以自定义线程创建的逻辑

7. private volatile RejectedExecutionHandler handler;  拒绝执行任务的处理器,可以自定义拒绝的策略

8. private volatile long keepAliveTime;   空闲线程的存活时间。可以根据这个存活时间来判断空闲线程是否等待超时,然后采取相应的线程回收操作

9. private volatile boolean allowCoreThreadTimeOut;  是否允许coreThread线程超时回收

10. private volatile int corePoolSize;  可存活的线程的最小值。如果设置了allowCoreThreadTimeOut, 那么corePoolSize的值可以为0。

11. private volatile int maximumPoolSize;  可存活的线程的最大值

 

工作线程创建和回收策略

ThreadPoolExecutor通过corePoolSize,maximumPoolSize, allowCoreThreadTimeOut,keepAliveTime等几个参数提供一个灵活的工作线程创建和回收的策略。

创建策略:

1. 当工作线程数量小于corePoolSize时,不管其他线程是否空闲,都创建新的工作线程来处理新加入的任务

2. 当工作线程数量大于corePoolSize,小于maximumPoolSize时,只有当工作队列满了,才会创建新的工作线程来处理新加入的任务。当工作队列有空余时,只把新任务加入队列

3. 把corePoolSize和maximumPoolSize 设置成相同的值时,线程池就是一个固定(fixed)工作线程数的线程。

回收策略:

1. keepAliveTime变量设置了空闲工作线程超时的时间,当工作线程数量超过了corePoolSize后,空闲的工作线程等待超过了keepAliveTime后,会被回收。后面会说怎么确定一个工作线程是否“空闲”。

2. 如果设置了allowCoreThreadTimeOut,那么core Thread也可以被回收,即当core thread也空闲时,也可以被回收,直到工作线程集合为0。

聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源码分析_第2张图片

工作队列策略

 

工作队列BlockingQueue workQueue 是用来存放提交的任务的。它有4个基本的策略,并且根据不同的阻塞队列的实现类可以引入更多的工作队列的策略。

4个基本策略:

1. 当工作线程数量小于corePoolSize时,新提交的任务总是会由新创建的工作线程执行,不入队列

2. 当工作线程数量大于corePoolSize,如果工作队列没满,新提交的任务就入队列

3. 当工作线程数量大于corePoolSize,小于MaximumPoolSize时,如果工作队列满了,新提交的任务就交给新创建的工作线程,不入队列

4. 当工作线程数量大于MaximumPoolSize,并且工作队列满了,那么新提交的任务会被拒绝执行。具体看采用何种拒绝策略

聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源码分析_第3张图片

根据不同的阻塞队列的实现类,又有几种额外的策略

1. 采用SynchronousQueue直接将任务传递给空闲的线程执行,不额外存储任务。这种方式需要无限制的MaximumPoolSize,可以创建无限制的工作线程来处理提交的任务。这种方式的好处是任务可以很快被执行,适用于任务到达时间大于任务处理时间的情况。缺点是当任务量很大时,会占用大量线程

2. 采用无边界的工作队列LinkedBlockingQueue。这种情况下,由于工作队列永远不会满,那么工作线程的数量最大就是corePoolSize,因为当工作线程数量达到corePoolSize时,只有工作队列满的时候才会创建新的工作线程。这种方式好处是使用的线程数量是稳定的,当内存足够大时,可以处理足够多的请求。缺点是如果任务直接有依赖,很有可能形成死锁,因为当工作线程被消耗完时,不会创建新的工作现场,只会把任务加入工作队列。并且可能由于内存耗尽引发内存溢出OOM

3. 采用有界的工作队列AraayBlockingQueue。这种情况下对于内存资源是可控的,但是需要合理调节MaximumPoolSize和工作队列的长度,这两个值是相互影响的。当工作队列长度比较小的时,必定会创建更多的线程。而更多的线程会引起上下文切换等额外的消耗。当工作队列大,MaximumPoolSize小的时候,会影响吞吐量,并且会触发拒绝机制。

 

拒绝执行策略

当Executor处于shutdown状态或者工作线程超过MaximumPoolSize并且工作队列满了之后,新提交的任务将会被拒绝执行。RejectedExecutionHandler接口定义了拒绝执行的策略。具体的策略有

CallerRunsPolicy:由调用者线程来执行被拒绝的任务,属于同步执行

AbortPolicy:中止执行,抛出RejectedExecutionException异常

DiscardPolicy:丢弃任务

DiscardOldestPolicy:丢弃最老的任务

 

 
  1. public static class CallerRunsPolicy implements RejectedExecutionHandler {

  2. /**

  3. * Creates a {@code CallerRunsPolicy}.

  4. */

  5. public CallerRunsPolicy() { }

  6.  
  7. /**

  8. * Executes task r in the caller's thread, unless the executor

  9. * has been shut down, in which case the task is discarded.

  10. *

  11. * @param r the runnable task requested to be executed

  12. * @param e the executor attempting to execute this task

  13. */

  14. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

  15. if (!e.isShutdown()) {

  16. r.run();

  17. }

  18. }

  19. }

  20.  
  21. /**

  22. * A handler for rejected tasks that throws a

  23. * {@code RejectedExecutionException}.

  24. */

  25. public static class AbortPolicy implements RejectedExecutionHandler {

  26. /**

  27. * Creates an {@code AbortPolicy}.

  28. */

  29. public AbortPolicy() { }

  30.  
  31. /**

  32. * Always throws RejectedExecutionException.

  33. *

  34. * @param r the runnable task requested to be executed

  35. * @param e the executor attempting to execute this task

  36. * @throws RejectedExecutionException always.

  37. */

  38. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

  39. throw new RejectedExecutionException("Task " + r.toString() +

  40. " rejected from " +

  41. e.toString());

  42. }

  43. }

  44.  
  45. /**

  46. * A handler for rejected tasks that silently discards the

  47. * rejected task.

  48. */

  49. public static class DiscardPolicy implements RejectedExecutionHandler {

  50. /**

  51. * Creates a {@code DiscardPolicy}.

  52. */

  53. public DiscardPolicy() { }

  54.  
  55. /**

  56. * Does nothing, which has the effect of discarding task r.

  57. *

  58. * @param r the runnable task requested to be executed

  59. * @param e the executor attempting to execute this task

  60. */

  61. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

  62. }

  63. }

  64.  
  65. /**

  66. * A handler for rejected tasks that discards the oldest unhandled

  67. * request and then retries {@code execute}, unless the executor

  68. * is shut down, in which case the task is discarded.

  69. */

  70. public static class DiscardOldestPolicy implements RejectedExecutionHandler {

  71. /**

  72. * Creates a {@code DiscardOldestPolicy} for the given executor.

  73. */

  74. public DiscardOldestPolicy() { }

  75.  
  76. /**

  77. * Obtains and ignores the next task that the executor

  78. * would otherwise execute, if one is immediately available,

  79. * and then retries execution of task r, unless the executor

  80. * is shut down, in which case task r is instead discarded.

  81. *

  82. * @param r the runnable task requested to be executed

  83. * @param e the executor attempting to execute this task

  84. */

  85. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

  86. if (!e.isShutdown()) {

  87. e.getQueue().poll();

  88. e.execute(r);

  89. }

  90. }

  91. }

 

工作线程Worker的设计

工作线程没有直接使用Thread,而是采用了Worker类封装了Thread,目的是更好地进行中断控制。Worker直接继承了AbstractQueuedSynchronizer来进行同步操作,它实现了一个不可重入的互斥结构。当它的state属性为0时表示unlock,state为1时表示lock。任务执行时必须在lock状态的保护下,防止出现同步问题。因此当Worker处于lock状态时,表示它正在运行,当它处于unlock状态时,表示它“空闲”。当它空闲超过keepAliveTime时,就有可能被回收。

Worker还实现了Runnable接口, 执行它的线程是Worker包含的Thread对象,在Worker的构造函数可以看到Thread创建时,把Worker对象传递给了它。

 

 
  1. private final class Worker

  2. extends AbstractQueuedSynchronizer

  3. implements Runnable

  4. {

  5.  
  6. /** Thread this worker is running in. Null if factory fails. */

  7. final Thread thread;

  8. /** Initial task to run. Possibly null. */

  9. Runnable firstTask;

  10. /** Per-thread task counter */

  11. volatile long completedTasks;

  12.  
  13. Worker(Runnable firstTask) {

  14. setState(-1); // inhibit interrupts until runWorker

  15. this.firstTask = firstTask;

  16.  
  17. // 把Worker对象作为Runnable的实例传递给了新创建Thread对象

  18.  this.thread = getThreadFactory().newThread(this);

  19. }

  20.  
  21. public void run() {

  22. runWorker(this);

  23. }

  24.  
  25. // Lock methods

  26. //

  27. // The value 0 represents the unlocked state.

  28. // The value 1 represents the locked state.

  29.  
  30. protected boolean isHeldExclusively() {

  31. return getState() != 0;

  32. }

  33.  
  34. protected boolean tryAcquire(int unused) {

  35. if (compareAndSetState(0, 1)) {

  36. setExclusiveOwnerThread(Thread.currentThread());

  37. return true;

  38. }

  39. return false;

  40. }

  41.  
  42. protected boolean tryRelease(int unused) {

  43. setExclusiveOwnerThread(null);

  44. setState(0);

  45. return true;

  46. }

  47.  
  48. public void lock() { acquire(1); }

  49. public boolean tryLock() { return tryAcquire(1); }

  50. public void unlock() { release(1); }

  51. public boolean isLocked() { return isHeldExclusively(); }

  52.  
  53. void interruptIfStarted() {

  54. Thread t;

  55. if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {

  56. try {

  57. t.interrupt();

  58. } catch (SecurityException ignore) {

  59. }

  60. }

  61. }

  62. }


Worker被它的线程执行时,run方法调用了ThreadPoolExecutor的runWorker方法。

1. wt指向当前执行Worker的run方法的线程,也就是指向了Worker包含的工作线程对象

2. task指向Worker包含的firstTask对象,表示当前要执行的任务

3. 当task不为null或者从工作队列中取到了新任务,那么先加锁w.lock表示正在运行任务。在真正开始执行task.run()之前,先判断线程池的状态是否已经STOP,如果是,就中断Worker的线程。

4. 一旦判断当前线程不是STOP并且工作线程没有中断。那么就开始执行task.run()了。Worker的interruptIfStarted方法可以中断这个Worker的线程,从而中断正在执行任务。

5. beforeExecute(wt, task)和afterExecute(wt,task)是两个钩子方法,支持在任务真正开始执行前就行扩展。

 

 
  1. final void runWorker(Worker w) {

  2. Thread wt = Thread.currentThread();

  3. Runnable task = w.firstTask;

  4. w.firstTask = null;

  5. w.unlock(); // allow interrupts

  6. boolean completedAbruptly = true;

  7. try {

  8. while (task != null || (task = getTask()) != null) {

  9. w.lock();

  10. // If pool is stopping, ensure thread is interrupted;

  11. // if not, ensure thread is not interrupted. This

  12. // requires a recheck in second case to deal with

  13. // shutdownNow race while clearing interrupt

  14. if ((runStateAtLeast(ctl.get(), STOP) ||

  15. (Thread.interrupted() &&

  16. runStateAtLeast(ctl.get(), STOP))) &&

  17. !wt.isInterrupted())

  18. wt.interrupt();

  19. try {

  20. beforeExecute(wt, task);

  21. Throwable thrown = null;

  22. try {

  23. task.run();

  24. } catch (RuntimeException x) {

  25. thrown = x; throw x;

  26. } catch (Error x) {

  27. thrown = x; throw x;

  28. } catch (Throwable x) {

  29. thrown = x; throw new Error(x);

  30. } finally {

  31. afterExecute(task, thrown);

  32. }

  33. } finally {

  34. task = null;

  35. w.completedTasks++;

  36. w.unlock();

  37. }

  38. }

  39. completedAbruptly = false;

  40. } finally {

  41. processWorkerExit(w, completedAbruptly);

  42. }

  43. }


工作线程Worker创建和回收的源码

首先看一下ThreadPoolExecutor的execute方法,这个方式是任务提交的入口。可以看到它的逻辑符合之前说的工作线程创建的基本策略

1. 当工作线程数量小于corePoolSize时,通过addWorker(command,true)来新建工作线程处理新建的任务,不入工作队列

2. 当工作线程数量大于等于corePoolSize时,先入队列,使用的是BlockingQueue的offer方法。当工作线程数量为0时,还会通过addWorker(null, false)添加一个新的工作线程

3. 当工作队列满了并且工作线程数量在corePoolSize和MaximumPoolSize之间,就创建新的工作线程去执行新添加的任务。当工作线程数量超过了MaximumPoolSize,就拒绝任务。

 

 
  1. public void execute(Runnable command) {

  2. if (command == null)

  3. throw new NullPointerException();

  4.  
  5. int c = ctl.get();

  6. if (workerCountOf(c) < corePoolSize) {

  7. if (addWorker(command, true))

  8. return;

  9. c = ctl.get();

  10. }

  11. if (isRunning(c) && workQueue.offer(command)) {

  12. int recheck = ctl.get();

  13. if (! isRunning(recheck) && remove(command))

  14. reject(command);

  15. else if (workerCountOf(recheck) == 0)

  16. addWorker(null, false);

  17. }

  18. else if (!addWorker(command, false))

  19. reject(command);

  20. }


可以看到addWorker方法是创建Worker工作线程的所在。

1. retry这个循环判断线程池的状态和当前工作线程数量的边界。如果允许创建工作现场,首先修改ctl变量表示的工作线程的数量

2. 把工作线程添加到workers集合中的操作要在mainLock这个锁的保护下进行。所有和ThreadPoolExecutor状态相关的操作都要在mainLock锁的保护下进行

3. w = new Worker(firstTask); 创建Worker实例,把firstTask作为它当前的任务。firstTask为null时表示先只创建Worker线程,然后去工作队列中取任务执行

4. 把新创建的Worker实例加入到workers集合,修改相关统计变量。

5. 当加入集合成功后,开始启动这个Worker实例。启动的方法是调用Worker封装的Thread的start()方法。之前说了,这个Thread对应的Runnable是Worker本身,会去调用Worker的run方法,然后调用ThreadPoolExecutor的runWorker方法。在runWorker方法中真正去执行任务。

 

 
  1. private boolean addWorker(Runnable firstTask, boolean core) {

  2. retry:

  3. for (;;) {

  4. int c = ctl.get();

  5. int rs = runStateOf(c);

  6.  
  7. // Check if queue empty only if necessary.

  8. if (rs >= SHUTDOWN &&

  9. ! (rs == SHUTDOWN &&

  10. firstTask == null &&

  11. ! workQueue.isEmpty()))

  12. return false;

  13.  
  14. for (;;) {

  15. int wc = workerCountOf(c);

  16. if (wc >= CAPACITY ||

  17. wc >= (core ? corePoolSize : maximumPoolSize))

  18. return false;

  19. if (compareAndIncrementWorkerCount(c))

  20. break retry;

  21. c = ctl.get(); // Re-read ctl

  22. if (runStateOf(c) != rs)

  23. continue retry;

  24. // else CAS failed due to workerCount change; retry inner loop

  25. }

  26. }

  27.  
  28. boolean workerStarted = false;

  29. boolean workerAdded = false;

  30. Worker w = null;

  31. try {

  32. final ReentrantLock mainLock = this.mainLock;

  33. w = new Worker(firstTask);

  34. final Thread t = w.thread;

  35. if (t != null) {

  36. mainLock.lock();

  37. try {

  38. // Recheck while holding lock.

  39. // Back out on ThreadFactory failure or if

  40. // shut down before lock acquired.

  41. int c = ctl.get();

  42. int rs = runStateOf(c);

  43.  
  44. if (rs < SHUTDOWN ||

  45. (rs == SHUTDOWN && firstTask == null)) {

  46. if (t.isAlive()) // precheck that t is startable

  47. throw new IllegalThreadStateException();

  48. workers.add(w);

  49. int s = workers.size();

  50. if (s > largestPoolSize)

  51. largestPoolSize = s;

  52. workerAdded = true;

  53. }

  54. } finally {

  55. mainLock.unlock();

  56. }

  57. if (workerAdded) {

  58. t.start();

  59. workerStarted = true;

  60. }

  61. }

  62. } finally {

  63. if (! workerStarted)

  64. addWorkerFailed(w);

  65. }

  66. return workerStarted;

  67. }


工作线程回收的方法是processWorkerExit(),它在runWorker方法执行结束的时候被调用。之前说了空闲的工作线程可能会在keepAliveTime时间之后被回收。这个逻辑隐含在runWorker方法和getTask方法中,会在下面说如何从工作队列取任务时说明。processWorkerExit方法单纯只是处理工作线程的回收。

1. 结合runWorker方法看,如果Worker执行task.run()的时候抛出了异常,那么completedAbruptly为true,需要从workers集合中把这个工作线程移除掉。

2. 如果是completedAbruptly为true,并且线程池不是STOP状态,那么就创建一个新的Worker工作线程

3. 如果是completedAbruptly为false,并且线程池不是STOP状态,首先检查是否allowCoreThreadTimeout,如果运行,那么最少线程数可以为0,否则是corePoolSize。如果最少线程数为0,并且工作队列不为空,那么最小值为1。最后检查当前的工作线程数量,如果小于最小值,就创建新的工作线程。

 

 
  1. private void processWorkerExit(Worker w, boolean completedAbruptly) {

  2. if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted

  3. decrementWorkerCount();

  4.  
  5. final ReentrantLock mainLock = this.mainLock;

  6. mainLock.lock();

  7. try {

  8. completedTaskCount += w.completedTasks;

  9. workers.remove(w);

  10. } finally {

  11. mainLock.unlock();

  12. }

  13.  
  14. tryTerminate();

  15.  
  16. int c = ctl.get();

  17. if (runStateLessThan(c, STOP)) {

  18. if (!completedAbruptly) {

  19. int min = allowCoreThreadTimeOut ? 0 : corePoolSize;

  20. if (min == 0 && ! workQueue.isEmpty())

  21. min = 1;

  22. if (workerCountOf(c) >= min)

  23. return; // replacement not needed

  24. }

  25. addWorker(null, false);

  26. }

  27. }


任务的获取

工作线程从工作队列中取任务的代码在getTask方法中

1. timed变量表示是否要计时,当计时超过keepAliveTime后还没取到任务,就返回null。结合runWorker方法可以知道,当getTask返回null时,该Worker线程会被回收,这就是如何回收空闲工作线程的方法。

timed变量当allowCoreThreadTimeout为true或者当工作线程数大于corePoolSize时为true。

2. 如果timed为true,就用BlockingQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)方法来计时从队头取任务,否则直接用take()方法从队头取任务

 

 
  1. private Runnable getTask() {

  2. boolean timedOut = false; // Did the last poll() time out?

  3.  
  4. retry:

  5. for (;;) {

  6. int c = ctl.get();

  7. int rs = runStateOf(c);

  8.  
  9. // Check if queue empty only if necessary.

  10. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {

  11. decrementWorkerCount();

  12. return null;

  13. }

  14.  
  15. boolean timed; // Are workers subject to culling?

  16.  
  17. for (;;) {

  18. int wc = workerCountOf(c);

  19. timed = allowCoreThreadTimeOut || wc > corePoolSize;

  20.  
  21. if (wc <= maximumPoolSize && ! (timedOut && timed))

  22. break;

  23. if (compareAndDecrementWorkerCount(c))

  24. return null;

  25. c = ctl.get(); // Re-read ctl

  26. if (runStateOf(c) != rs)

  27. continue retry;

  28. // else CAS failed due to workerCount change; retry inner loop

  29. }

  30.  
  31. try {

  32. Runnable r = timed ?

  33. workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :

  34. workQueue.take();

  35. if (r != null)

  36. return r;

  37. timedOut = true;

  38. } catch (InterruptedException retry) {

  39. timedOut = false;

  40. }

  41. }

  42. }


线程池的关闭

线程池有SHUTDOWN, STOP, TIDYING, TERMINATED这几个状态和线程池关闭相关。通常我们把关闭分为优雅的关闭和强制立刻关闭。

所谓优雅的关闭就是调用shutdown()方法,线程池进入SHUTDOWN状态,不在接收新的任务,会把工作队列的任务执行完毕后再结束。

强制立刻关闭就是调用shutdownNow()方法,线程池直接进入STOP状态,会中断正在执行的工作线程,清空工作队列。

1. 在shutdown方法中,先设置线程池状态为SHUTDOWN,然后先去中断空闲的工作线程,再调用onShutdown钩子方法。最后tryTerminate()

2. 在shutdownNow方法中,先设置线程池状态为STOP,然后先中断所有的工作线程,再清空工作队列。最后tryTerminate()。这个方法会把工作队列中的任务返回给调用者处理。

 

 
  1. public void shutdown() {

  2. final ReentrantLock mainLock = this.mainLock;

  3. mainLock.lock();

  4. try {

  5. checkShutdownAccess();

  6. advanceRunState(SHUTDOWN);

  7. interruptIdleWorkers();

  8. onShutdown(); // hook for ScheduledThreadPoolExecutor

  9. } finally {

  10. mainLock.unlock();

  11. }

  12. tryTerminate();

  13. }

  14.  
  15.   public List shutdownNow() {

  16.         List tasks;

  17.         final ReentrantLock mainLock = this.mainLock;

  18.         mainLock.lock();

  19.         try {

  20.             checkShutdownAccess();

  21.             advanceRunState(STOP);

  22.             interruptWorkers();

  23.             tasks = drainQueue();

  24.         } finally {

  25.             mainLock.unlock();

  26.         }

  27.         tryTerminate();

  28.         return tasks;

  29.     }


interruptIdleWorkers方法会去中断空闲的工作线程,所谓空闲的工作线程即没有上锁的Worker。

而interruptWorkers方法直接去中断所有的Worker,调用Worker.interruptIfStarted()方法

 

 
  1. private void interruptIdleWorkers(boolean onlyOne) {

  2. final ReentrantLock mainLock = this.mainLock;

  3. mainLock.lock();

  4. try {

  5. for (Worker w : workers) {

  6. Thread t = w.thread;

  7. if (!t.isInterrupted() && w.tryLock()) {

  8. try {

  9. t.interrupt();

  10. } catch (SecurityException ignore) {

  11. } finally {

  12. w.unlock();

  13. }

  14. }

  15. if (onlyOne)

  16. break;

  17. }

  18. } finally {

  19. mainLock.unlock();

  20. }

  21. }

  22.  
  23.  private void interruptWorkers() {

  24.         final ReentrantLock mainLock = this.mainLock;

  25.         mainLock.lock();

  26.         try {

  27.             for (Worker w : workers)

  28.                 w.interruptIfStarted();

  29.         } finally {

  30.             mainLock.unlock();

  31.         }

  32.     }

  33.  
  34.   void interruptIfStarted() {

  35.             Thread t;

  36.             if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {

  37.                 try {

  38.                     t.interrupt();

  39.                 } catch (SecurityException ignore) {

  40.                 }

  41.             }

  42.         }


tryTerminate方法会尝试终止线程池,根据线程池的状态,在相应状态会中断空闲工作线程,调用terminated()钩子方法,设置状态为TERMINATED。

 

 
  1. final void tryTerminate() {

  2. for (;;) {

  3. int c = ctl.get();

  4. if (isRunning(c) ||

  5. runStateAtLeast(c, TIDYING) ||

  6. (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))

  7. return;

  8. if (workerCountOf(c) != 0) { // Eligible to terminate

  9. interruptIdleWorkers(ONLY_ONE);

  10. return;

  11. }

  12.  
  13. final ReentrantLock mainLock = this.mainLock;

  14. mainLock.lock();

  15. try {

  16. if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {

  17. try {

  18. terminated();

  19. } finally {

  20. ctl.set(ctlOf(TERMINATED, 0));

  21. termination.signalAll();

  22. }

  23. return;

  24. }

  25. } finally {

  26. mainLock.unlock();

  27. }

  28. // else retry on failed CAS

  29. }

  30. }


最后说明一下,JVM的守护进程只有当所有派生出来的线程都结束后才会退出,使用ThreadPoolExecutor线程池时,如果有的任务一直执行,并且不响应中断,那么会一直占用线程,那么JVM也会一直工作,不会退出。

你可能感兴趣的:(Java)