ThreadPoolExecutor原理概述

在我们的开发中“池”的概念并不罕见,有数据库连接池、线程池、对象池、常量池等等。下面我们主要针对线程池来一步一步揭开线程池的面纱。

使用线程池的好处

1、降低资源消耗

可以重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度

当任务到达时,任务可以不需要等到线程创建就能立即执行。

3、提高线程的可管理性

线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控

线程池的工作原理

首先我们看下当一个新的任务提交到线程池之后,线程池是如何处理的

1、线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则执行第二步。

2、线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里进行等待。如果工作队列满了,则执行第三步

3、线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务

线程池饱和策略

这里提到了线程池的饱和策略,那我们就简单介绍下有哪些饱和策略:

AbortPolicy

为Java线程池默认的阻塞策略,不执行此任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute需要try catch,否则程序会直接退出。

DiscardPolicy

直接抛弃,任务不执行,空方法

DiscardOldestPolicy

从队列里面抛弃head的一个任务,并再次execute 此task。

CallerRunsPolicy

在调用execute的线程里面执行此command,会阻塞入口

用户自定义拒绝策略(最常用)

实现RejectedExecutionHandler,并自己定义策略模式

下我们以ThreadPoolExecutor为例展示下线程池的工作流程图

1、如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。

2、如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。

3、如果无法将任务加入BlockingQueue(队列已满),则在非corePool中创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。

4、如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。

线程池状态以及含义
RUNNING        运行态
SHUTDOWN    关闭,此时不接受新的任务,但继续处理队列中的任务。
STOP                停止,此时不接受新的任务,不处理队列中的任务,并中断正在执行的任务
TIDYING          所有的工作线程全部停止,并工作线程数量为0,将调用terminated方法,进入到TERMINATED
TERMINATED  终止状态
-------------------------------------------------------------------
ThreadPoolExecutor原理详细解析
1、ThreadPoolExecutor概述
    由于本人英语水平不高,为了不误导大家,我将源码中的注释复制下来,我不翻译原文,我从入学6个视角试图窥探一下ThreadPoolExecutor全貌。
1)创建线程池的方式
2)核心线程数、最大线程数
3)线程的创建
4)线程的Keep-alive(保持存活的空闲时间)
5)队列

6)任务的丢弃策略

/** * An {@link ExecutorService} that executes each submitted task using * one of possibly several pooled threads, normally configured * using {@link Executors} factory methods. * * <p>Thread pools address two different problems: they usually * provide improved performance when executing large numbers of * asynchronous tasks, due to reduced per-task invocation overhead, * and they provide a means of bounding and managing the resources, * including threads, consumed when executing a collection of tasks. * Each {@code ThreadPoolExecutor} also maintains some basic * statistics, such as the number of completed tasks. * * <p>To be useful across a wide range of contexts, this class * provides many adjustable parameters and extensibility * hooks. However, programmers are urged to use the more convenient * {@link Executors} factory methods {@link * Executors#newCachedThreadPool} (unbounded thread pool, with * automatic thread reclamation), {@link Executors#newFixedThreadPool} * (fixed size thread pool) and {@link * Executors#newSingleThreadExecutor} (single background thread), that * preconfigure settings for the most common usage * scenarios. Otherwise, use the following guide when manually * configuring and tuning this class: * 1、提供如下工厂方法创建线程池对象(ExecutorService实现类) 1)Executors.newCachedThreadPool,创建一个线程容量为Integer.MAX_VALUE的线程池,空闲时间为60s。 2)Executors.newFixedThreadPool,创建一个固定容量的线程池 3)Executors.newSingleThreadExecutor,创建一个线程的线程池 * <dl> *核心线程与最大线程篇 * <dt>Core and maximum pool sizes</dt>
corePoolSize 核心线程数
maximumPoolSize 核心线程数
当一个任务提交到线程池
1) 如果当前线程池中的线程数小于corePoolSize时,直接创建一个先的线程。
2) 如果当前线程池中的线程数大于等于corePoolSize时,如果队列未满,直接将线程放入队列中,不新建线程。
3) 如果队列已满,但线程没有超过maximumPoolSize,则新建一个线程。 在运行过程中,可以通过调用setCorePoolSize,setMaximumPoolSize改变这两个参数 * * <dd>A {@code ThreadPoolExecutor} will automatically adjust the * pool size (see {@link #getPoolSize}) * according to the bounds set by * corePoolSize (see {@link #getCorePoolSize}) and * maximumPoolSize (see {@link #getMaximumPoolSize}). * * When a new task is submitted in method {@link #execute}, and fewer * than corePoolSize threads are running, a new thread is created to * handle the request, even if other worker threads are idle.  If * there are more than corePoolSize but less than maximumPoolSize * threads running, a new thread will be created only if the queue is * full.  By setting corePoolSize and maximumPoolSize the same, you * create a fixed-size thread pool. By setting maximumPoolSize to an * essentially unbounded value such as {@code Integer.MAX_VALUE}, you * allow the pool to accommodate an arbitrary number of concurrent * tasks. Most typically, core and maximum pool sizes are set only * upon construction, but they may also be changed dynamically using * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd> *    * * * <dt>On-demand construction</dt *  核心线程的创建通常是有任务提交时新建的,当然,我们可以通过调用prestartCoreThread,或              prestartAllCoreThreads方法,预先创建核心线程数。 * <dd> By default, even core threads are initially created and * started only when new tasks arrive, but this can be overridden * dynamically using method {@link #prestartCoreThread} or {@link * #prestartAllCoreThreads}.  You probably want to prestart threads if * you construct the pool with a non-empty queue. </dd> * * <dt>Creating new threads</dt> *线程创建篇,新线程的创建,默认使用Executors.defautThreadFactory来创建线程,同一个线程创建工厂创建的线程具有相同的线程组,优先级,是否是后台线程(daemon),我们可以提供资金的线程创建工厂来改变这些属性,一般我们使用自己定义的线程工厂,主要的目的还是修改线程的名称,方便理解与跟踪。 * <dd>New threads are created using a {@link ThreadFactory}.  If not * otherwise specified, a {@link Executors#defaultThreadFactory} is * used, that creates threads to all be in the same {@link * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and * non-daemon status. By supplying a different ThreadFactory, you can * alter the thread's name, thread group, priority, daemon status, * etc. If a {@code ThreadFactory} fails to create a thread when asked * by returning null from {@code newThread}, the executor will * continue, but might not be able to execute any tasks. Threads * should possess the "modifyThread" {@code RuntimePermission}. If * worker threads or other threads using the pool do not possess this * permission, service may be degraded: configuration changes may not * take effect in a timely manner, and a shutdown pool may remain in a * state in which termination is possible but not completed.</dd> * * <dt>Keep-alive times</dt> * 如果线程池中线程数量超过了核心线程数,超过的线程如果空闲时间超过了keepAliveTime的线程会被终止; 先提出一个疑问:如果核心线程数设置为10,目前有12个线程,其中有3个超过了keepALiveTime,那有3个线程会被终止,还是只有两个,按照上述描述,应该是2个会被终止,,因为有个管家子 excess threads,从源码中去找答案吧。 * <dd>If the pool currently has more than corePoolSize threads, * excess threads will be terminated if they have been idle for more * than the keepAliveTime (see {@link #getKeepAliveTime}). This * provides a means of reducing resource consumption when the pool is * not being actively used. If the pool becomes more active later, new * threads will be constructed. This parameter can also be changed * dynamically using method {@link #setKeepAliveTime}. Using a value * of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively * disables idle threads from ever terminating prior to shut down. By * default, the keep-alive policy applies only when there are more * than corePoolSizeThreads. But method {@link * #allowCoreThreadTimeOut(boolean)} can be used to apply this * time-out policy to core threads as well, so long as the * keepAliveTime value is non-zero. </dd> * * <dt>Queuing</dt> * * <dd>Any {@link BlockingQueue} may be used to transfer and hold * submitted tasks.  The use of this queue interacts with pool sizing: * * <ul> * * <li> If fewer than corePoolSize threads are running, the Executor * always prefers adding a new thread * rather than queuing.</li> * * <li> If corePoolSize or more threads are running, the Executor * always prefers queuing a request rather than adding a new * thread.</li> * * <li> If a request cannot be queued, a new thread is created unless * this would exceed maximumPoolSize, in which case, the task will be * rejected.</li> * * </ul> * * There are three general strategies for queuing: 三种队列方案 1)直接传递,所有提交任务任务不入队列,直接传递给线程池。 2)有界队列 3)无界队列 采取何种队列,会对线程池中 核心线程数产生影响 再重复一下 核心线程的产生过程 1)如果当前线程池中线程数小于核心线程数,新任务到达,不管有没有队列,都是直接新建一个核心线程。 2)如果线程池中允许的线程达到核心线程数量时,根据不同的队列机制,有如下的处理方法: a、如果是直接传递,则直接新增线程运行(没有达到最大线程数量) b、如果是有界队列,先将任务入队列,如果任务队列已满,在线程数没有超过最大线程数限制的情况下,新 建一个线程来运行任务。 c、无界队列,则线程池中最大的线程数量等于核心线程数量,最大线程数量不会有产生任何影响。 * <ol> * * <li> <em> Direct handoffs.</em> A good default choice for a work * queue is a {@link SynchronousQueue} that hands off tasks to threads * without otherwise holding them. Here, an attempt to queue a task * will fail if no threads are immediately available to run it, so a * new thread will be constructed. This policy avoids lockups when * handling sets of requests that might have internal dependencies. * Direct handoffs generally require unbounded maximumPoolSizes to * avoid rejection of new submitted tasks. This in turn admits the * possibility of unbounded thread growth when commands continue to * arrive on average faster than they can be processed.  </li> * * <li><em> Unbounded queues.</em> Using an unbounded queue (for * example a {@link LinkedBlockingQueue} without a predefined * capacity) will cause new tasks to wait in the queue when all * corePoolSize threads are busy. Thus, no more than corePoolSize * threads will ever be created. (And the value of the maximumPoolSize * therefore doesn't have any effect.)  This may be appropriate when * each task is completely independent of others, so tasks cannot * affect each others execution; for example, in a web page server. * While this style of queuing can be useful in smoothing out * transient bursts of requests, it admits the possibility of * unbounded work queue growth when commands continue to arrive on * average faster than they can be processed.  </li> * * <li><em>Bounded queues.</em> A bounded queue (for example, an * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when * used with finite maximumPoolSizes, but can be more difficult to * tune and control.  Queue sizes and maximum pool sizes may be traded * off for each other: Using large queues and small pools minimizes * CPU usage, OS resources, and context-switching overhead, but can * lead to artificially low throughput.  If tasks frequently block (for * example if they are I/O bound), a system may be able to schedule * time for more threads than you otherwise allow. Use of small queues * generally requires larger pool sizes, which keeps CPUs busier but * may encounter unacceptable scheduling overhead, which also * decreases throughput.  </li> * * </ol> * * </dd> * * <dt>Rejected tasks</dt> *   任务拒绝策略 1)AbortPolicy,抛出运行时异常 2)CallerRunsPolicy 调用者直接运行,不在线程中运行。 3)DiscardPolicy  直接将任务丢弃 4)DiscardOldestPolicy  丢弃队列中头部的任务。 * <dd> New tasks submitted in method {@link #execute} will be * <em>rejected</em> when the Executor has been shut down, and also * when the Executor uses finite bounds for both maximum threads and * work queue capacity, and is saturated.  In either case, the {@code * execute} method invokes the {@link * RejectedExecutionHandler#rejectedExecution} method of its {@link * RejectedExecutionHandler}.  Four predefined handler policies are * provided: * * <ol> * * <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the * handler throws a runtime {@link RejectedExecutionException} upon * rejection. </li> * * <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread * that invokes {@code execute} itself runs the task. This provides a * simple feedback control mechanism that will slow down the rate that * new tasks are submitted. </li> * * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that * cannot be executed is simply dropped.  </li> * * <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the * executor is not shut down, the task at the head of the work queue * is dropped, and then execution is retried (which can fail again, * causing this to be repeated.) </li> * * </ol> * * It is possible to define and use other kinds of {@link * RejectedExecutionHandler} classes. Doing so requires some care * especially when policies are designed to work only under particular * capacity or queuing policies. </dd> * * <dt>Hook methods</dt> * * <dd>This class provides {@code protected} overridable {@link * #beforeExecute} and {@link #afterExecute} methods that are called * before and after execution of each task.  These can be used to * manipulate the execution environment; for example, reinitializing * ThreadLocals, gathering statistics, or adding log * entries. Additionally, method {@link #terminated} can be overridden * to perform any special processing that needs to be done once the * Executor has fully terminated. * * <p>If hook or callback methods throw exceptions, internal worker * threads may in turn fail and abruptly terminate.</dd> * * <dt>Queue maintenance</dt> * * <dd> Method {@link #getQueue} allows access to the work queue for * purposes of monitoring and debugging.  Use of this method for any * other purpose is strongly discouraged.  Two supplied methods, * {@link #remove} and {@link #purge} are available to assist in * storage reclamation when large numbers of queued tasks become * cancelled.</dd> * * <dt>Finalization</dt> * * <dd> A pool that is no longer referenced in a program <em>AND</em> * has no remaining threads will be {@code shutdown} automatically. If * you would like to ensure that unreferenced pools are reclaimed even * if users forget to call {@link #shutdown}, then you must arrange * that unused threads eventually die, by setting appropriate * keep-alive times, using a lower bound of zero core threads and/or * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd> * * </dl> * * <p> <b>Extension example</b>. Most extensions of this class * override one or more of the protected hook methods. For example, * here is a subclass that adds a simple pause/resume feature: * *  <pre> {@code * class PausableThreadPoolExecutor extends ThreadPoolExecutor { *   private boolean isPaused; *   private ReentrantLock pauseLock = new ReentrantLock(); *   private Condition unpaused = pauseLock.newCondition(); * *   public PausableThreadPoolExecutor(...) { super(...); } * *   protected void beforeExecute(Thread t, Runnable r) { *     super.beforeExecute(t, r); *     pauseLock.lock(); *     try { *       while (isPaused) unpaused.await(); *     } catch (InterruptedException ie) { *       t.interrupt(); *     } finally { *       pauseLock.unlock(); *     } *   } * *   public void pause() { *     pauseLock.lock(); *     try { *       isPaused = true; *     } finally { *       pauseLock.unlock(); *     } *   } * *   public void resume() { *     pauseLock.lock(); *     try { *       isPaused = false; *       unpaused.signalAll(); *     } finally { *       pauseLock.unlock(); *     } *   } * }}</pre> * * @since 1.5 * @author Doug Lea */  

2、ThreadPoolExecutors 内部数据结构与构造方法详解

ThreadPoolExecutors的完整构造函数如下,从构造函数中能得出线程池最核心的属性

[java]view plaincopy
  1. /**
  2. * Creates a new {@code ThreadPoolExecutor} with the given initial
  3. * parameters.
  4. *
  5. * @param corePoolSize the number of threads to keep in the pool, even
  6. *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
  7. * @param maximumPoolSize the maximum number of threads to allow in the
  8. *        pool
  9. * @param keepAliveTime when the number of threads is greater than
  10. *        the core, this is the maximum time that excess idle threads
  11. *        will wait for new tasks before terminating.
  12. * @param unit the time unit for the {@code keepAliveTime} argument
  13. * @param workQueue the queue to use for holding tasks before they are
  14. *        executed.  This queue will hold only the {@code Runnable}
  15. *        tasks submitted by the {@code execute} method.
  16. * @param threadFactory the factory to use when the executor
  17. *        creates a new thread
  18. * @param handler the handler to use when execution is blocked
  19. *        because the thread bounds and queue capacities are reached
  20. * @throws IllegalArgumentException if one of the following holds:<br>
  21. *         {@code corePoolSize < 0}<br>
  22. *         {@code keepAliveTime < 0}<br>
  23. *         {@code maximumPoolSize <= 0}<br>
  24. *         {@code maximumPoolSize < corePoolSize}
  25. * @throws NullPointerException if {@code workQueue}
  26. *         or {@code threadFactory} or {@code handler} is null
  27. */
  28. public ThreadPoolExecutor(int corePoolSize,
  29. int maximumPoolSize,
  30. long keepAliveTime,
  31. TimeUnit unit,
  32. BlockingQueue<Runnable> workQueue,
  33. ThreadFactory threadFactory,
  34. RejectedExecutionHandler handler) {
  35. if (corePoolSize < 0 ||
  36. maximumPoolSize <= 0 ||
  37. maximumPoolSize < corePoolSize ||
  38. keepAliveTime < 0)
  39. throw new IllegalArgumentException();
  40. if (workQueue == null || threadFactory == null || handler == null)
  41. throw new NullPointerException();
  42. this.corePoolSize = corePoolSize;
  43. this.maximumPoolSize = maximumPoolSize;
  44. this.workQueue = workQueue;
  45. this.keepAliveTime = unit.toNanos(keepAliveTime);
  46. this.threadFactory = threadFactory;
  47. this.handler = handler;
  48. }

2、ThreadPoolExecutors 内部数据结构与构造方法详解

1) corePoolSize 核心线程数
2)maximumPoolSize 最大线程数
3)keepAliveTime 线程保持激活状态的时间,如果为0,永远处于激活状态
4)unit ,keepAliveTime的单位
5)workQueue,线程池使用的队列
6)threadFactory 创建线程的工厂
7)handler 当队列已满,无更大线程处理任务时的拒绝任务的策略。
除了这些核心参数外,我觉得有必要再关注如下
8)HashSet<Worker> workers
9)completedTaskCount 完成的任务数
10)allowCoreThreadTimeOut,该值默认为false,也就是默认keepAliveTime不会生效。
3、核心源码分析
3.1 线程状态与几个基础方法设计原理
[java]view plaincopy
  1. /**
  2. * The main pool control state, ctl, is an atomic integer packing
  3. * two conceptual fields
  4. *   workerCount, indicating the effective number of threads
  5. *   runState,    indicating whether running, shutting down etc
  6. *
  7. * In order to pack them into one int, we limit workerCount to
  8. * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
  9. * billion) otherwise representable. If this is ever an issue in
  10. * the future, the variable can be changed to be an AtomicLong,
  11. * and the shift/mask constants below adjusted. But until the need
  12. * arises, this code is a bit faster and simpler using an int.
  13. *
  14. * The workerCount is the number of workers that have been
  15. * permitted to start and not permitted to stop.  The value may be
  16. * transiently different from the actual number of live threads,
  17. * for example when a ThreadFactory fails to create a thread when
  18. * asked, and when exiting threads are still performing
  19. * bookkeeping before terminating. The user-visible pool size is
  20. * reported as the current size of the workers set.
  21. *
  22. * The runState provides the main lifecyle control, taking on values:
  23. *
  24. *   RUNNING:  Accept new tasks and process queued tasks
  25. *   SHUTDOWN: Don't accept new tasks, but process queued tasks
  26. *   STOP:     Don't accept new tasks, don't process queued tasks,
  27. *             and interrupt in-progress tasks
  28. *   TIDYING:  All tasks have terminated, workerCount is zero,
  29. *             the thread transitioning to state TIDYING
  30. *             will run the terminated() hook method
  31. *   TERMINATED: terminated() has completed
  32. *
  33. * The numerical order among these values matters, to allow
  34. * ordered comparisons. The runState monotonically increases over
  35. * time, but need not hit each state. The transitions are:
  36. *
  37. * RUNNING -> SHUTDOWN
  38. *    On invocation of shutdown(), perhaps implicitly in finalize()
  39. * (RUNNING or SHUTDOWN) -> STOP
  40. *    On invocation of shutdownNow()
  41. * SHUTDOWN -> TIDYING
  42. *    When both queue and pool are empty
  43. * STOP -> TIDYING
  44. *    When pool is empty
  45. * TIDYING -> TERMINATED
  46. *    When the terminated() hook method has completed
  47. *
  48. * Threads waiting in awaitTermination() will return when the
  49. * state reaches TERMINATED.
  50. *
  51. * Detecting the transition from SHUTDOWN to TIDYING is less
  52. * straightforward than you'd like because the queue may become
  53. * empty after non-empty and vice versa during SHUTDOWN state, but
  54. * we can only terminate if, after seeing that it is empty, we see
  55. * that workerCount is 0 (which sometimes entails a recheck -- see
  56. * below).
  57. */
  58. private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
  59. private static final int COUNT_BITS = Integer.SIZE - 3;
  60. private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
  61. // runState is stored in the high-order bits
  62. private static final int RUNNING    = -1 << COUNT_BITS;
  63. private static final int SHUTDOWN   =  0 << COUNT_BITS;
  64. private static final int STOP       =  1 << COUNT_BITS;
  65. private static final int TIDYING    =  2 << COUNT_BITS;
  66. private static final int TERMINATED =  3 << COUNT_BITS;
  67. // Packing and unpacking ctl
  68. private static int runStateOf(int c)     { return c & ~CAPACITY; }
  69. private static int workerCountOf(int c)  { return c & CAPACITY; }
  70. private static int ctlOf(int rs, int wc) { return rs | wc; }
  71. private static boolean isRunning(int c) {
  72. return c < SHUTDOWN;
  73. }

2、ThreadPoolExecutors 内部数据结构与构造方法详解

相关源码解读:
不知大家有没有,为什么线程池的状态简单的定义为 -1,0,1,2,3不就得了,为什么还要用移位操作呢?
原来这样的,ThreadPool
ctl的这个变量的设计哲学是用int的高3位 + 29个0代表状态,,用高位000+低29位来表示线程池中工作线程的数量,太佩服了。
首先CAPACITY的值为workCount的最大容量,该值为 000 11111 11111111 11111111 11111111,29个1,
我们来看一下
private static int runStateOf(int c)     { return c & ~CAPACITY; }
用ctl里面的值与容量取反的方式获取状态值。由于CAPACITY的值为000 11111 11111111 11111111 11111111,那取反后为111 00000 00000000 00000000 00000000, 用 c 与 该值进行与运算,这样就直接保留了c的高三位,然后将c的低29位设置为0,这不就是线程池状态的存放规则吗,绝。
根据此方法,不难得出计算workCount的方法。
private static int ctlOf(int rs, int wc) { return rs | wc; }
该方法,主要是用来更新运行状态的。确保工作线程数量不丢失。
线程池状态以及含义
RUNNING        运行态
SHUTDOWN    关闭,此时不接受新的任务,但继续处理队列中的任务。
STOP                停止,此时不接受新的任务,不处理队列中的任务,并中断正在执行的任务
TIDYING          所有的工作线程全部停止,并工作线程数量为0,将调用terminated方法,进入到TERMINATED
TERMINATED  终止状态
线程池默认状态 RUNNING
如果调用shutdwon() 方法,状态从 RUNNING --->  SHUTDOWN
如果调用shutdwonNow()方法,状态从RUUNING|SHUTDOWN--->STOP
SHUTDOWN ---> TIDYING 
队列为空并且线程池空
STOP --> TIDYING
线程池为空
线程池设计原理:
1)线程池的工作线程为ThreadPoolExecutors的Worker线程,无论是submit还是executor方法中传入的Callable task,Runable参数,只是实现了Runnable接口,在线程池的调用过程,不会调用其start方法,只会调用Worker线程的start方法,然后在Worker线程的run方法中会调用入参的run方法。
2)众所周知,线程的生命周期在run方法运行结束后(包括异常退出)就结束。要想重复利用线程,我们要确保工作线程Worker的run方法运行在一个无限循环中,然后从任务队列中一个一个获取对象,如果任务队列为空,则阻塞,当然需要提供一些控制,结束无限循环,来销毁线程。在源码 runWorker方法与getTask来实现。 
大概的实现思路是 如果getTask返回null,则该worker线程将被销毁。
那getTask在什么情况下会返回false呢?
1、如果线程池的状态为SHUTDOWN并且队列不为空
2、如果线程池的状态大于STOP
3、如果当前运行的线程数大于核心线程数,会返回null,已销毁该worker线程
对keepAliveTime的理解,如果allowCoreThreadTimeOut为真,那么keepAliveTime其实就是从任务队列获取任务等待的超时时间,也就是workerQueue.poll(keepALiveTime, TimeUnit.NANOSECONDS)
3.2 <T> FUture<T> submit(Callable<T> task) 方法详解
在看的代码的过程中,只要明白了上述基础方法,后面的代码看起来清晰可见,故,我只列出关键方法,大家可以浏览,应该不难。
[java]view plaincopy
  1. /**
  2. * Submits a value-returning task for execution and returns a
  3. * Future representing the pending results of the task. The
  4. * Future's <tt>get</tt> method will return the task's result upon
  5. * successful completion.
  6. *
  7. * <p>
  8. * If you would like to immediately block waiting
  9. * for a task, you can use constructions of the form
  10. * <tt>result = exec.submit(aCallable).get();</tt>
  11. *
  12. * <p> Note: The {@link Executors} class includes a set of methods
  13. * that can convert some other common closure-like objects,
  14. * for example, {@link java.security.PrivilegedAction} to
  15. * {@link Callable} form so they can be submitted.
  16. *
  17. * @param task the task to submit
  18. * @return a Future representing pending completion of the task
  19. * @throws RejectedExecutionException if the task cannot be
  20. *         scheduled for execution
  21. * @throws NullPointerException if the task is null
  22. */
  23. <T> Future<T> submit(Callable<T> task);
  24. 提交一个任务,并返回结构到Future,Future就是典型的Future设计模式,就是提交任务到线程池后,返回一个凭证,并直接返回,主线程继续执行,然后当线程池将任务运行完毕后,再将结果填充到凭证中,当主线程调用凭证future的get方法时,如果结果还未填充,则阻塞等待。
  25. 现将Callable与Future接口的源代码贴出来,然后重点分析submit方法的实现。
  26. public interface Callable<V> {
  27. /**
  28. * Computes a result, or throws an exception if unable to do so.
  29. *
  30. * @return computed result
  31. * @throws Exception if unable to compute a result
  32. */
  33. V call() throws Exception;
  34. }
  35. public interface Future<V> {
  36. /**
  37. * Attempts to cancel execution of this task.  This attempt will
  38. * fail if the task has already completed, has already been cancelled,
  39. * or could not be cancelled for some other reason. If successful,
  40. * and this task has not started when <tt>cancel</tt> is called,
  41. * this task should never run.  If the task has already started,
  42. * then the <tt>mayInterruptIfRunning</tt> parameter determines
  43. * whether the thread executing this task should be interrupted in
  44. * an attempt to stop the task.
  45. *
  46. * <p>After this method returns, subsequent calls to {@link #isDone} will
  47. * always return <tt>true</tt>.  Subsequent calls to {@link #isCancelled}
  48. * will always return <tt>true</tt> if this method returned <tt>true</tt>.
  49. *
  50. * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
  51. * task should be interrupted; otherwise, in-progress tasks are allowed
  52. * to complete
  53. * @return <tt>false</tt> if the task could not be cancelled,
  54. * typically because it has already completed normally;
  55. * <tt>true</tt> otherwise
  56. */
  57. boolean cancel(boolean mayInterruptIfRunning);
  58. /**
  59. * Returns <tt>true</tt> if this task was cancelled before it completed
  60. * normally.
  61. *
  62. * @return <tt>true</tt> if this task was cancelled before it completed
  63. */
  64. boolean isCancelled();
  65. /**
  66. * Returns <tt>true</tt> if this task completed.
  67. *
  68. * Completion may be due to normal termination, an exception, or
  69. * cancellation -- in all of these cases, this method will return
  70. * <tt>true</tt>.
  71. *
  72. * @return <tt>true</tt> if this task completed
  73. */
  74. boolean isDone();
  75. /**
  76. * Waits if necessary for the computation to complete, and then
  77. * retrieves its result.
  78. *
  79. * @return the computed result
  80. * @throws CancellationException if the computation was cancelled
  81. * @throws ExecutionException if the computation threw an
  82. * exception
  83. * @throws InterruptedException if the current thread was interrupted
  84. * while waiting
  85. */
  86. V get() throws InterruptedException, ExecutionException;
  87. /**
  88. * Waits if necessary for at most the given time for the computation
  89. * to complete, and then retrieves its result, if available.
  90. *
  91. * @param timeout the maximum time to wait
  92. * @param unit the time unit of the timeout argument
  93. * @return the computed result
  94. * @throws CancellationException if the computation was cancelled
  95. * @throws ExecutionException if the computation threw an
  96. * exception
  97. * @throws InterruptedException if the current thread was interrupted
  98. * while waiting
  99. * @throws TimeoutException if the wait timed out
  100. */
  101. V get(long timeout, TimeUnit unit)
  102. throws InterruptedException, ExecutionException, TimeoutException;
  103. }
  104. 现在开始探究submit的实现原理,该代码出自AbstractExecutorService中
  105. public Future<?> submit(Runnable task) {
  106. if (task == null) throw new NullPointerException();
  107. RunnableFuture<Void> ftask = newTaskFor(task, null);
  108. execute(ftask);
  109. return ftask;
  110. }
  111. protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
  112. return new FutureTask<T>(callable);
  113. }
  114. 核心实现在ThreadPoolExecutor的execute方法
  115. /**
  116. * Executes the given task sometime in the future.  The task
  117. * may execute in a new thread or in an existing pooled thread.
  118. *
  119. * If the task cannot be submitted for execution, either because this
  120. * executor has been shutdown or because its capacity has been reached,
  121. * the task is handled by the current {@code RejectedExecutionHandler}.
  122. *
  123. * @param command the task to execute
  124. * @throws RejectedExecutionException at discretion of
  125. *         {@code RejectedExecutionHandler}, if the task
  126. *         cannot be accepted for execution
  127. * @throws NullPointerException if {@code command} is null
  128. */
  129. public void execute(Runnable command) {
  130. if (command == null)
  131. throw new NullPointerException();
  132. /*
  133. * Proceed in 3 steps:
  134. *
  135. * 1. If fewer than corePoolSize threads are running, try to
  136. * start a new thread with the given command as its first
  137. * task.  The call to addWorker atomically checks runState and
  138. * workerCount, and so prevents false alarms that would add
  139. * threads when it shouldn't, by returning false.
  140. *
  141. * 2. If a task can be successfully queued, then we still need
  142. * to double-check whether we should have added a thread
  143. * (because existing ones died since last checking) or that
  144. * the pool shut down since entry into this method. So we
  145. * recheck state and if necessary roll back the enqueuing if
  146. * stopped, or start a new thread if there are none.
  147. *
  148. * 3. If we cannot queue task, then we try to add a new
  149. * thread.  If it fails, we know we are shut down or saturated
  150. * and so reject the task.
  151. */
  152. int c = ctl.get();
  153. if (workerCountOf(c) < corePoolSize) {  // @1
  154. if (addWorker(command, true))         // @2
  155. return;
  156. c = ctl.get();                                         //@3
  157. }
  158. if (isRunning(c) && workQueue.offer(command)) {
  159. int recheck = ctl.get();
  160. if (! isRunning(recheck) && remove(command))
  161. reject(command);
  162. else if (workerCountOf(recheck) == 0)
  163. addWorker(null, false);
  164. }
  165. else if (!addWorker(command, false))
  166. reject(command);
  167. }
  168. 代码@1,如果当前线程池中的线程数量小于核心线程数的话,尝试新增一个新的线程。所以我们把目光投入到addWorker方法中。
  169. addWorker源码详解:
  170. /**
  171. * Checks if a new worker can be added with respect to current
  172. * pool state and the given bound (either core or maximum). If so,
  173. * the worker count is adjusted accordingly, and, if possible, a
  174. * new worker is created and started, running firstTask as its
  175. * first task. This method returns false if the pool is stopped or
  176. * eligible to shut down. It also returns false if the thread
  177. * factory fails to create a thread when asked.  If the thread
  178. * creation fails, either due to the thread factory returning
  179. * null, or due to an exception (typically OutOfMemoryError in
  180. * Thread#start), we roll back cleanly.
  181. *
  182. * @param firstTask the task the new thread should run first (or
  183. * null if none). Workers are created with an initial first task
  184. * (in method execute()) to bypass queuing when there are fewer
  185. * than corePoolSize threads (in which case we always start one),
  186. * or when the queue is full (in which case we must bypass queue).
  187. * Initially idle threads are usually created via
  188. * prestartCoreThread or to replace other dying workers.
  189. *
  190. * @param core if true use corePoolSize as bound, else
  191. * maximumPoolSize. (A boolean indicator is used here rather than a
  192. * value to ensure reads of fresh values after checking other pool
  193. * state).
  194. * @return true if successful
  195. */
  196. private boolean addWorker(Runnable firstTask, boolean core) {
  197. retry:
  198. for (;;) { // @1
  199. int c = ctl.get();
  200. int rs = runStateOf(c);   // @2
  201. // Check if queue empty only if necessary.
  202. if (rs >= SHUTDOWN &&                                       //@3
  203. ! (rs == SHUTDOWN &&
  204. firstTask == null &&
  205. ! workQueue.isEmpty()))
  206. return false;
  207. for (;;) {  //@4
  208. int wc = workerCountOf(c);
  209. if (wc >= CAPACITY ||
  210. wc >= (core ? corePoolSize : maximumPoolSize))              //@5
  211. return false;
  212. if (compareAndIncrementWorkerCount(c))
  213. break retry;     // @6
  214. c = ctl.get();  // Re-read ctl
  215. if (runStateOf(c) != rs)
  216. continue retry;   //@7
  217. // else CAS failed due to workerCount change; retry inner loop
  218. }
  219. }
  220. boolean workerStarted = false;
  221. boolean workerAdded = false;
  222. Worker w = null;
  223. try {
  224. final ReentrantLock mainLock = this.mainLock;
  225. w = new Worker(firstTask);
  226. final Thread t = w.thread;
  227. if (t != null) {
  228. mainLock.lock();          // @8
  229. try {
  230. // Recheck while holding lock.
  231. // Back out on ThreadFactory failure or if
  232. // shut down before lock acquired.
  233. int c = ctl.get();
  234. int rs = runStateOf(c);
  235. if (rs < SHUTDOWN ||
  236. (rs == SHUTDOWN && firstTask == null)) {
  237. if (t.isAlive()) // precheck that t is startable
  238. throw new IllegalThreadStateException();
  239. workers.add(w);
  240. int s = workers.size();
  241. if (s > largestPoolSize)
  242. largestPoolSize = s;
  243. workerAdded = true;
  244. }
  245. } finally {
  246. mainLock.unlock();
  247. }
  248. if (workerAdded) {
  249. t.start();             // 运行线程 // @9
  250. workerStarted = true;
  251. }  //@8 end
  252. }
  253. } finally {
  254. if (! workerStarted)
  255. addWorkerFailed(w);   // 增加工作线程失败
  256. }
  257. return workerStarted;
  258. }
  259. 代码@1,外层循环(自旋模式)
  260. 代码@2,获取线程池的运行状态
  261. 代码@3,这里的判断条件,为什么不直接写 if(rs >= SHUTDOWN) return false;而要加第二个条件,目前不明白,等在了解到参数firstTask在什么情况下为空。在这里,我们目前只要知道,只有线程池的状态为 RUNNING时,线程池才接收新的任务,去增加工作线程。
  262. 代码@4,内层循环,主要的目的就是利用CAS增加一个线程数量。
  263. 代码@5,判断当前线程池的数量,如果数量达到规定的数量,则直接返回false,添加工作线程失败。
  264. 代码@6,如果修改线程数量成功,则跳出循环,开始创建工作线程。
  265. 代码@7,如果修改线程数量不成功(CAS)有两种情况:1、线程数量变化,重试则好,2,如果线程的运行状态变化,则重新开始外层循环,重新判断addWork流程。
  266. 代码@8,在锁mainLock的保护下,完成 workers (HashSet)的维护。
  267. 接着分析一下代码@9,启动线程,执行关键的方法 runWorker方法:
  268. /**
  269. * Main worker run loop.  Repeatedly gets tasks from queue and
  270. * executes them, while coping with a number of issues:
  271. *
  272. * 1. We may start out with an initial task, in which case we
  273. * don't need to get the first one. Otherwise, as long as pool is
  274. * running, we get tasks from getTask. If it returns null then the
  275. * worker exits due to changed pool state or configuration
  276. * parameters.  Other exits result from exception throws in
  277. * external code, in which case completedAbruptly holds, which
  278. * usually leads processWorkerExit to replace this thread.
  279. *
  280. * 2. Before running any task, the lock is acquired to prevent
  281. * other pool interrupts while the task is executing, and
  282. * clearInterruptsForTaskRun called to ensure that unless pool is
  283. * stopping, this thread does not have its interrupt set.
  284. *
  285. * 3. Each task run is preceded by a call to beforeExecute, which
  286. * might throw an exception, in which case we cause thread to die
  287. * (breaking loop with completedAbruptly true) without processing
  288. * the task.
  289. *
  290. * 4. Assuming beforeExecute completes normally, we run the task,
  291. * gathering any of its thrown exceptions to send to
  292. * afterExecute. We separately handle RuntimeException, Error
  293. * (both of which the specs guarantee that we trap) and arbitrary
  294. * Throwables.  Because we cannot rethrow Throwables within
  295. * Runnable.run, we wrap them within Errors on the way out (to the
  296. * thread's UncaughtExceptionHandler).  Any thrown exception also
  297. * conservatively causes thread to die.
  298. *
  299. * 5. After task.run completes, we call afterExecute, which may
  300. * also throw an exception, which will also cause thread to
  301. * die. According to JLS Sec 14.20, this exception is the one that
  302. * will be in effect even if task.run throws.
  303. *
  304. * The net effect of the exception mechanics is that afterExecute
  305. * and the thread's UncaughtExceptionHandler have as accurate
  306. * information as we can provide about any problems encountered by
  307. * user code.
  308. *
  309. * @param w the worker
  310. */
  311. final void runWorker(Worker w) {
  312. Thread wt = Thread.currentThread();
  313. Runnable task = w.firstTask;
  314. w.firstTask = null;
  315. w.unlock(); // allow interrupts
  316. boolean completedAbruptly = true;
  317. try {
  318. while (task != null || (task = getTask()) != null) {
  319. w.lock();
  320. // If pool is stopping, ensure thread is interrupted;
  321. // if not, ensure thread is not interrupted.  This
  322. // requires a recheck in second case to deal with
  323. // shutdownNow race while clearing interrupt
  324. if ((runStateAtLeast(ctl.get(), STOP) ||
  325. (Thread.interrupted() &&
  326. runStateAtLeast(ctl.get(), STOP))) &&
  327. !wt.isInterrupted())
  328. wt.interrupt();
  329. try {
  330. beforeExecute(wt, task);
  331. Throwable thrown = null;
  332. try {
  333. task.run();
  334. } catch (RuntimeException x) {
  335. thrown = x; throw x;
  336. } catch (Error x) {
  337. thrown = x; throw x;
  338. } catch (Throwable x) {
  339. thrown = x; throw new Error(x);
  340. } finally {
  341. afterExecute(task, thrown);
  342. }
  343. } finally {
  344. task = null;
  345. w.completedTasks++;
  346. w.unlock();
  347. }
  348. }
  349. completedAbruptly = false;
  350. } finally {
  351. processWorkerExit(w, completedAbruptly);
  352. }
  353. }
  354. /**
  355. * Performs blocking or timed wait for a task, depending on
  356. * current configuration settings, or returns null if this worker
  357. * must exit because of any of:
  358. * 1. There are more than maximumPoolSize workers (due to
  359. *    a call to setMaximumPoolSize).
  360. * 2. The pool is stopped.
  361. * 3. The pool is shutdown and the queue is empty.
  362. * 4. This worker timed out waiting for a task, and timed-out
  363. *    workers are subject to termination (that is,
  364. *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
  365. *    both before and after the timed wait.
  366. *
  367. * @return task, or null if the worker must exit, in which case
  368. *         workerCount is decremented
  369. */
  370. private Runnable getTask() {
  371. boolean timedOut = false; // Did the last poll() time out?
  372. retry:
  373. for (;;) {
  374. int c = ctl.get();
  375. int rs = runStateOf(c);
  376. // Check if queue empty only if necessary.
  377. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
  378. decrementWorkerCount();
  379. return null;
  380. }
  381. boolean timed;      // Are workers subject to culling?
  382. for (;;) {
  383. int wc = workerCountOf(c);
  384. timed = allowCoreThreadTimeOut || wc > corePoolSize;
  385. if (wc <= maximumPoolSize && ! (timedOut && timed))
  386. break;
  387. if (compareAndDecrementWorkerCount(c))
  388. return null;
  389. c = ctl.get();  // Re-read ctl
  390. if (runStateOf(c) != rs)
  391. continue retry;
  392. // else CAS failed due to workerCount change; retry inner loop
  393. }
  394. try {
  395. Runnable r = timed ?
  396. workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
  397. workQueue.take();
  398. if (r != null)
  399. return r;
  400. timedOut = true;
  401. } catch (InterruptedException retry) {
  402. timedOut = false;
  403. }
  404. }
  405. }

Java 线程池(ThreadPoolExecutor)原理分析与使用相关推荐

  1. Java 线程池(ThreadPoolExecutor)原理分析与使用 – 码农网

    线程池的详解 Java 线程池(ThreadPoolExecutor)原理分析与使用 – 码农网 http://www.codeceo.com/article/java-threadpool-exec ...

  2. Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  3. Java线程池ThreadPoolExecutor使用和分析

    Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) Java线程池ThreadPoolExecutor使用和分析(三 ...

  4. 【有料】Java线程池实现原理及其在美团业务中的实践

    随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供的线程池:ThreadPoolExecutor类,帮助开发人员 ...

  5. 【源码阅读计划】浅析 Java 线程池工作原理及核心源码

    [源码阅读计划]浅析 Java 线程池工作原理及核心源码 为什么要用线程池? 线程池的设计 线程池如何维护自身状态? 线程池如何管理任务? execute函数执行过程(分配) getTask 函数(获 ...

  6. Java 线程池的原理与实现

    最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知识空白的 ...

  7. java线程池ThreadPoolExecutor类详解

    线程池有哪些状态 1. RUNNING:  接收新的任务,且执行等待队列中的任务 Accept new tasks and process queued tasks  2. SHUTDOWN: 不接收 ...

  8. JAVA线程池(ThreadPoolExecutor)源码分析

    JAVA5提供了多种类型的线程池,如果你对这些线程池的特点以及类型不太熟悉或者非常熟悉,请帮忙看看这篇文章(顺便帮忙解决里面存在的问题,谢谢!):     http://xtu-xiaoxin.ite ...

  9. Java线程池实现原理及其在美团业务中的实践

    来自:美团技术团队 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供的线程池ThreadPoolExecuto ...

最新文章

  1. EXCEL中SUMIF函数介绍
  2. python爬虫 django搜索修改更新数据_django_数据库操作—增、删、改、查
  3. 大学计算机一条指令的执行过程实验,实验四 一条指令的执行过程
  4. HTTP metadata数据
  5. 随着通信和编程,它是一门艺术系列3(沟通的目的)
  6. Apache Kafka源码剖析:第5篇 业务API处理
  7. marker主题 ros_(五)ROS主题理解
  8. 计算机辅助应用的缩写有什么,计算机辅助设计的英文缩写是什么
  9. pageResponse - 让H5适配移动设备全家(移动端适配)
  10. MySQL is running but PID file could not be found(在macOS系统下解决方法)
  11. leetcode898.BitwiseORsofSubarrays
  12. ActiveMQ 消息游标(Message Cursors)
  13. 项目管理工具project软件学习(四) - 日历保存为模板、日历重命名、删除
  14. MPB:遗传发育所刘永鑫等-易扩增子:易用、可重复和跨平台的扩增子分析流程...
  15. 十进制和二十进制的转换
  16. QTP/UFT能捕捉到对象但是点击不了,录制点击也没反应
  17. Principal branch
  18. 互联网——常见英文缩写及其含义
  19. 决定系数 均方误差mse_【机器学习】回归误差:MSE、RMSE、MAE、R2、Adjusted R2 +方差、协方差、标准差(标准偏差/均方差)、均方误差、均方根误差(标准误差)、均方根解释...
  20. Little Red Riding Hood(动态规划)

热门文章

  1. 单列模式(懒汉)测试代码
  2. CentOS7安装Docker详细教程
  3. 智能合约重构社会契约(10)超级账本之跨链Hyperledger Lab
  4. C++ Primer 5th笔记(chap 12 动态内存)weak_ptr
  5. 现代密码学4.1--消息完整性
  6. 2021中青杯数学建模A题 汽车组装车间流水线物料配送问题
  7. linux kernel中的wait_for_completion和complete总结
  8. [toolchains]-ARM ToolChains介绍
  9. C语言获取数组越界,除以零等异常
  10. angr学习笔记(2)