java 线程池源码复习

目录

一、线程池的目的和初衷

二、ThreadPoolExecutor的几个主要的状态、每个状态特点、各状态之间相互转变的触发以及条件

三、ThreadPoolExecutor的关键参数

四、关键参数的作用和相互关系

五、常用任务队列的策列

六、工作线程类的解析

七、这里讲解一下Thread.interrupt() 方便理解下面的interruptIdleWorkers()

八、关键方法的解析


主要通过对 java.util.concurrent.ThreadPoolExecutor 源码进行研究学习

一、线程池的目的和初衷

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.
线程池解决了两个不同的问题:它们通常在执行大量异步任务时提供更好的性能,因为减少了每个任务的调用开销,并且它们提供了一种限制和管理执行任务集合时所消耗的系统资源(包括线程)的方法。每个{@code ThreadPoolExecutor}还维护一些基本统计数据,例如已完成任务的数量。

二、ThreadPoolExecutor的几个主要的状态、每个状态特点、各状态之间相互转变的触发以及条件

//保存当前线程池实例的运行状态 和 工作线程数
//1.运行状态保存在二进制表示的 最高三位 工作线程是保存在二进制表示的剩下29位
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

int CAPACITY = (1 << 29) - 1 = 00011111 11111111 11111111 11111111
                   ~CAPACITY = 11100000 00000000 00000000 00000000

// runState is stored in the high-order bits
// 线程池的运行状态,保存在 ctl 最高三位

//正常运行状态 接收新的任务 同时 也处理任务队列中的任务
//Accept new tasks and process queued tasks
private static final int RUNNING    = -1 << 29;
 
-1的源码 10000000 00000000 00000000 00000001
-1的反码 11111111 11111111 11111111 11111110
-1的反码 11111111 11111111 11111111 11111111

RUNNING = -1 << 29
        = 11111111 11111111 11111111 11111111 << 29 
        = 11100000 00000000 00000000 00000000

//Don't accept new tasks, but process queued tasks
//不接收新任务,但是还会继续处理任务队列中的任务
private static final int SHUTDOWN   =  0 << 29;

SHUTDOWN = 000000000 00000000 00000000 00000000


//Don't accept new tasks, don't process queued tasks,
//and interrupt in-progress tasks
//不接收新任务,不处理任务队列中的任务,还要中断处理中的任务
private static final int STOP       =  1 << 29;

STOP = 1 << 29
     = 00000000 00000000 00000000 00000001
     = 00100000 00000000 00000000 00000000


//All tasks have terminated, workerCount is zero,the thread 
//transitioning to state TIDYING will run the terminated() hook method
//所有的任务都已经终结,工作线程数为0,将状态转变为 TIDYING 的那个线程会执行
//钩子函数terminated()
private static final int TIDYING    =  2 << 29;

TIDYING = 2 << 29
     = 00000000 00000000 00000000 00000010
     = 01000000 00000000 00000000 00000000


//terminated() has completed
//执行完terminated() 之后就变为 TERMINATED
private static final int TERMINATED =  3 << 29;

TERMINATED = 3 << 29
     = 00000000 00000000 00000000 00000011
     = 01100000 00000000 00000000 00000000



RUNNING -> SHUTDOWN
On invocation of shutdown(), perhaps implicitly in finalize()
//shutdown()方法被调用,或者在finalize()方法中隐性的由RUNNING变为SHUTDOWN
//ThreadPoolExecutor 重写了finalize() 方法,也就是该ThreadPoolExecutor实例
//不被任何变量引用的时候,就会被自动垃圾回收,在回收之前会调用finalize()方法
//ThreadPoolExecutor 重写了finalize(),并且在其中调用shutdown(),为了资源回收

/**
 * Invokes {@code shutdown} when this executor is no longer
 * referenced and it has no threads.
 */
protected void finalize() {
    SecurityManager sm = System.getSecurityManager();
    if (sm == null || acc == null) {
        shutdown();
    } else {
        PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
        AccessController.doPrivileged(pa, acc);
    }
}


(RUNNING or SHUTDOWN) -> STOP
On invocation of shutdownNow()
//在RUNNING or SHUTDOWN状态下 调用shutdownNow()

SHUTDOWN -> TIDYING
When both queue and pool are empty
//在SHUTDOWN状态下检测到 任务队列 和 工作线程池都为空

STOP -> TIDYING
When pool is empty
//在STOP状态下检测到工作线程池为空


TIDYING -> TERMINATED
When the terminated() hook method has completed
//在TIDYING状态下成功调用terminated()方法


Threads waiting in awaitTermination() will return when the
state reaches TERMINATED.
//当状态变为 TERMINATED 之后,通过awaitTermination() 方法等待
//的线程都会返回


Detecting the transition from SHUTDOWN to TIDYING is less
straightforward than you'd like because the queue may become
 empty after non-empty and vice versa during SHUTDOWN state, but
 we can only terminate if, after seeing that it is empty, we see
 that workerCount is 0 (which sometimes entails a recheck -- see below).
//监测 从SHUTDOWN到TIDYING的转变没有想的那么简单,因为在SHUTDOWN状态下,
//对列非空之后又可能变为空,反之亦然,但是我们只能在看到 队列为空并且,我们看到
//工作线程数为0的时候进行终结(有时候我们需要再次检测)。



// Packing and unpacking ctl  对 ctl 进行打包或者拆包

 
// 从 ctl 中拆出代表运行状态的 最高 3 位 
private static int runStateOf(int c) {
    // ~CAPACITY = 11100000 00000000 00000000 00000000
    // 可以看到任何一个数字与 ~CAPACITY 进行 与运算,最高位 3 位
    // 不变,剩下的29位都会是 0. 
    return c & ~CAPACITY; 
}

// 从 ctl 中拆出代表工作线程数的剩下 29 位
private static int workerCountOf(int c) {
    // CAPACITY = 00011111 11111111 11111111 11111111
    // 可以看到任何一个数字与 CAPACITY 进行 与运算,最高位 3 位都会变为0
    // 剩下的29位都不变. 
    return c & CAPACITY; 
}

// 将rs中代表运行状态的最高 3 位,和wc中代表工作线程数的 低 29 位拼接起来
private static int ctlOf(int rs, int wc) {
    //这里之所以可以使用 或运算 把rs的最高3位和wc中的低29位拼接起来
    //是因为 rs 是最高3位是有效位,剩下的29位都是0
    //wc是 最高3位为0,剩下的29位是有效位
    return rs | wc; 
}

三、ThreadPoolExecutor的关键参数


/**
 * The queue used for holding tasks and handing off to worker
 * threads.  We do not require that workQueue.poll() returning
 * null necessarily means that workQueue.isEmpty(), so rely
 * solely on isEmpty to see if the queue is empty (which we must
 * do for example when deciding whether to transition from
 * SHUTDOWN to TIDYING).  This accommodates special-purpose
 * queues such as DelayQueues for which poll() is allowed to
 * return null even if it may later return non-null when delays
 * expire.
 *
 * 这个队列用于持有任务并传递给工作线程。我们不要求workQueue.poll()
 * 返回 null 就一定代表workQueue.isEmpty(),因此我们只能依靠isEmpty
 * 来判断队列是否为空。(例如当我们在决定是否从SHUTDOWN转变为TIDYING
 * 的时候,我们必须这样做)。这适应了特殊用途的队列,如DelayQueues,
 * 对于这些队列,poll()允许返回null,即使在延迟到期时可能会返回非null。
 *
 */
private final BlockingQueue<Runnable> workQueue;

/**
 * Set containing all worker threads in pool. Accessed only when
 * holding mainLock.
 * 包含所有工作线程的集合,只有在获取到 mainlock 的情况下才能访问
 * 这里其实算是真正意义上的线程池了
 */
private final HashSet<Worker> workers = new HashSet<Worker>();


/**
 * Factory for new threads. All threads are created using this
 * factory (via method addWorker).  All callers must be prepared
 * for addWorker to fail, which may reflect a system or user's
 * policy limiting the number of threads.  Even though it is not
 * treated as an error, failure to create threads may result in
 * new tasks being rejected or existing ones remaining stuck in
 * the queue.
 * 创建新线程的工厂,所有的线程都是通过addWorker方法,用这个工厂创建
 * 的,所有调用addWorker的地方都做好添加失败的准备,这反映了系统或者
 * 用户限制线程数的策略。尽管没有将其当作一个Error,创建线程失败可能
 * 会导致新任务被拒绝,或者已有的任务任然被卡在队列里
 *
 * We go further and preserve pool invariants even in the face of
 * errors such as OutOfMemoryError, that might be thrown while
 * trying to create threads.  Such errors are rather common due to
 * the need to allocate a native stack in Thread.start, and users
 * will want to perform clean pool shutdown to clean up.  There
 * will likely be enough memory available for the cleanup code to
 * complete without encountering yet another OutOfMemoryError.
 * 我们更进一步,即使在尝试创建线程时可能会抛出OutOfMemoryError等错误
 * 的情况下,也会保留池不变量。由于需要在Thread.start中分配本机堆栈,
 * 此类错误很常见,用户将希望执行清理池关闭以进行清理。可能有足够的可
 * 用内存来完成清理代码,而不会遇到另一个OutOfMemoryError。
 *
 *
 */
private volatile ThreadFactory threadFactory;


/**
 * Handler called when saturated or shutdown in execute.
 * 当线程池已经包和或者已经处于shutdown状态,这时候如果通过
 * execute()方法继续执行任务,就会使用 handler 进行处理
 *
 */
private volatile RejectedExecutionHandler handler;


/**
 * Timeout in nanoseconds for idle threads waiting for work.
 * Threads use this timeout when there are more than corePoolSize
 * present or if allowCoreThreadTimeOut. Otherwise they wait
 * forever for new work.
 * 空闲线程等待任务的超时的时间,当现有的工作线程数超过 corePoolSize,
 * 或者 allowCoreThreadTimeOut == true的时候,工作线程在获取任务时会
 * 使用这个超时时间。否则他们获取任务时就会一直等待,没有超时
 *
 */
private volatile long keepAliveTime;

/**
 * If false (default), core threads stay alive even when idle.
 * If true, core threads use keepAliveTime to time out waiting
 * for work.
 * 默认 false,核心线程空闲的时候任然保持存活
 * 如果 true,核心线程在等待任务时,使用 keepAliveTime 作为超时时间
 *
 */
private volatile boolean allowCoreThreadTimeOut;

/**
 * Core pool size is the minimum number of workers to keep alive
 * (and not allow to time out etc) unless allowCoreThreadTimeOut
 * is set, in which case the minimum is zero.
 * corePoolSize 是保持存活的工作线程数的最小值,并且不容许超时,
 * 除非 allowCoreThreadTimeOut == true,在这种情况下最小值为 0
 *
 */
private volatile int corePoolSize;

/**
 * Maximum pool size. Note that the actual maximum is internally
 * bounded by CAPACITY.
 * 最大活动线程数,注意实际的最大值在内部被 CAPACITY 限制
 *
 */
private volatile int maximumPoolSize;

四、关键参数的作用和相互关系

When a new task is submitted in method execute(Runnable),
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 
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 setCorePoolSize and setMaximumPoolSize.
当一个新任务通过execute(Runnable)方法提交执行时,并且存活的线程数小于
corePoolSize,就会创建一个新的线程处理这个任务,即使其他存活的工作线程
处于空闲状态。如果存活的工作线程大于corePoolSize但是小于maximumPoolSize,
那么只有在任务队列满了之后才会创建一个心线程来执行新提交的任务。
通过把corePoolSize 和 maximumPoolSize 设置成一样的,就可以创建一个固定
大小的线程池(这里的意思是,如果corePoolSize 和 maximumPoolSize相同,
那么当存活的线程达到corePoolSize的同时也达到了maximumPoolSize,这样如果提交
新任务,就会放入任务队列,不会马上创建新的工作线程,这样就等于是一个固定大小
线程池)。通过将maximumPoolSize设置为一个基本上无限的值,就可以容许线程池容纳
无限数量的任务。通常,核心线程数和最大线程数是在创建的时候设定,但是也可以通
过setCorePoolSize 和 setMaximumPoolSize对其进行修改



On-demand construction

By default, even core threads are initially created and started only when 
new tasks arrive, but this can be overridden dynamically using method 
prestartCoreThread or prestartAllCoreThreads. You probably want to prestart 
threads if you construct the pool with a non-empty queue.
默认情况下核心线程只有在新任务到达时才会创建并启动,但是这种情况可以通过
prestartCoreThread 和 prestartAllCoreThreads 这样个方法动态重写。如果你创建
线程池的时候使用的是一个非空的任务队列(创建线程池用的任务队列已经加入了若干
线程任务),那么你可能想提前启动若干工作线程来对非空任务队列中的任务进行处理,
而不是等到新任务被提交的时候才创建并启动工作线程

    @Test
    public void nonEmptyQueue() throws InterruptedException {

        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
        workQueue.add(() -> System.out.println("我是提前加入任务队列的一个任务"));

        ThreadPoolExecutor threadPoolExecutor 
                = new ThreadPoolExecutor(3, 3 , 1 , TimeUnit.SECONDS , workQueue);
        threadPoolExecutor.prestartCoreThread();

        TimeUnit.SECONDS.sleep(2);

    }


Creating new threads

New threads are created using a ThreadFactory.  If not
otherwise specified, a Executors#defaultThreadFactory is
used, that creates threads to all be in the same 
ThreadGroup and with the same 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 ThreadFactory fails to create a thread when asked
by returning null from newThread, the executor will
continue, but might not be able to execute any tasks. Threads
should possess the "modifyThread" 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.
线程池的线程是通过一个ThreadFactory实例创建的,如果没有指定专门的
ThreadFactory实例,默认使用Executors#defaultThreadFactory方法返回的
ThreadFactory实例。这个ThreadFactory创建的线程都在同一个线程组(thread group)
下,优先级都是 NORM_PRIORITY,都是非守护线程。
通过提供不同的ThreadFactory实例,我们可以修改创建的线程的名字,所属的线程组
优先级,和是否是守护线程等等。 ThreadFactory实例通过newThread方法创建线程失败
返回null,线程池实例还会继续,但是不能执行任何任务(因为任务需要创建出来的线程
执行)。线程应该拥有"modifyThread" RuntimePermission(运行时修改线程的权限),
如果工作线程或者线程池的其他线程不拥有这个权限,服务就会降级,配置改变不能
即时生效,shutdown的线程池可能处于一种可能终止,但未完成的状态


Keep-alive times

If the pool currently has more than corePoolSize threads,
excess threads will be terminated if they have been idle for more
than the keepAliveTime getKeepAliveTime(TimeUnit).
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 setKeepAliveTime(long,TimeUnit). 
 Using a value of Long.MAX_VALUE 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 corePoolSize threads. But method 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.
如果当前工作线程数大于corePoolSize,那么空闲超过keepAliveTime时间
(keepAliveTime 是通过 getKeepAliveTime(TimeUnit)的返回的 ) 的工作线程会
被终结掉。这提供了一种在线程池不是特别忙碌时,减少资源占用的方法。如果之后
线程池又变的更加忙碌,新的线程会被创建。keepAliveTime这个参数也可以通过
setKeepAliveTime(long,TimeUnit)方法来动态修改。使用一个Long.MAX_VALUE的值
作为keepAliveTime的值,可以有效地(effectively )禁止空闲线程在关闭前(prior to之前)
终止. 默认情况下是在工作线程数大于corePoolSize的时候才会采用 keep-alive 策略。但是
设置allowCoreThreadTimeOut==true可以使超时策略应用到核心线程,只要keepAliveTime非0


Queuing

Any BlockingQueue may be used to transfer and hold
submitted tasks.  The use of this queue interacts with pool sizing:
任何BlockingQueue实例都可以被用来传递或者持有提交的任务

If fewer than corePoolSize threads are running, the Executor
always prefers adding a new thread rather than queuing.
如果工作线程数小于corePoolSize,线程池偏向于添加一个新线程执行新提交的任务
,而不是将新任务放入队列中


If corePoolSize or more threads are running, the Executor
always prefers queuing a request rather than adding a new thread.
如果工作线程数大于等于corePoolSize,线程池偏向于将新任务放入队列中,而不是
添加一个新线程执行新提交的任务

If a request cannot be queued, a new thread is created unless
this would exceed maximumPoolSize, in which case, the task will be rejected.
如果新提交的请求任务不能放入队列(可能使队列满了),那么除非创建一个新线程以后,工作线程
超过maximumPoolSize,要不就会创建一个新的线程来执行新任务。如果不能放入队列,同时也大于
maximumPoolSize,那么这个新任务会被拒绝

五、常用任务队列的策列

Direct handoffs.
手递手传球队列 

A good default choice for a work
queue is a 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.

SynchronousQueue是任务队列的一种不错的选择,这种队列不会持有任务,而是
直接将任务传递给工作线程。往SynchronousQueue实例里放任务都会失败(调用
SynchronousQueue对象的add方法的时候会报错 java.lang.IllegalStateException: 
Queue full),所以如果立刻没有一个可用的工作线程来执行新提交的任务,一个新的
工作线程就会被创建。此策略在处理可能具有内部依赖关系的请求集时避免了锁定(这里的
意思就是,任务来了之后直接交给工作线程执行,所以先来的任务先被执行,防止了后提交
的线程先被执行,比如两个任务,第一个任务提交的时候队列没有满所以入队了,第二个
任务提交的时候,队列满了,所以可能会新创建一个线程来执行第二个任务,这样就会导致,
先提交的任务后执行)。手递手传递这种队列策略通常需要无限大的maximumPoolSizes来避免
新提交的任务被拒绝(入队失败,同时达到maximumPoolSizes,就会拒绝)。这反过来承认当任务
提交速度持续大于任务被处理的速度的时候,工作线程数无限增长的可能性。因为入队失败并且
没有到达maximumPoolSizes的时候就会创建新的工作线程。


Unbounded queues. 
无界队列,也就是如果内存足够大,队列可以一直往里放

Using an unbounded queue (for example a 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.
使用一个无界队列,例如一个LinkedBlockingQueue没有提前为其设置容量,这回导致当
所有的核心线程都在忙的时候,新提交的任务在队列中等待。这样就不会有超过corePoolSize
的工作线程被创建,这种情况下maximumPoolSize没有任何作用。当每个任务之间完全相互独立,
任务之间的执行互不影响的时候,这种策列挺合适的。例如在一个web page 服务中,这种风格的
队列对于平滑的处理瞬时的爆量请求是有用(把爆量的请求都放入队列,然后让工作线程匀速从
队列里取出处理),这就相当于承认了当任务提交的速度大于处理的平均速度时,任务队列无限增长
的可能性。


Bounded queues. 
有界队列,创建队列的时候会提前规定队列的大小,只要不超过队列的大小就可以往里放


A bounded queue (for example, an 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.
一个有界队列,例如一个ArrayBlockingQueue(提前设定好容量),同时设置有限的
maximumPoolSizes,可以防止资源耗尽(主要是线程资源,内存资源),但是调整和控制
起来比较困难。队列容量大小和maximumPoolSize可能会相互权衡。使用大容量的队列和小
的maximumPoolSizes可以减小cpu使用率、系统资源、和上下文切换的开销,但是可能导致
人为的低吞吐量。如果任务经常阻塞(例如,如果它们受到I/O限制),系统可能能够为比您
允许的更多的线程安排时间(意思就是如果我们提交的任务被阻塞,那么可以cpu可以被调度
去完成一些不是我们提交的任务,等阻塞解除之后,再调度回来完成我们提交的任务).
如果使用小容量的队列通常需要大的maximumPoolSizes,这样会保持cpu更加忙,也就是cpu
的使用率提高,但是可能会导致不可接受的调度开销,这同样也会降低吞吐量

六、工作线程类的解析

/**
 * Class Worker mainly maintains interrupt control state for
 * threads running tasks, along with other minor bookkeeping.
 * This class opportunistically extends AbstractQueuedSynchronizer
 * to simplify acquiring and releasing a lock surrounding each
 * task execution.  This protects against interrupts that are
 * intended to wake up a worker thread waiting for a task from
 * instead interrupting a task being run.  We implement a simple
 * non-reentrant mutual exclusion lock rather than use
 * ReentrantLock because we do not want worker tasks to be able to
 * reacquire the lock when they invoke pool control methods like
 * setCorePoolSize.  Additionally, to suppress interrupts until
 * the thread actually starts running tasks, we initialize lock
 * state to a negative value, and clear it upon start (in
 * runWorker).
 * Worker类的主要职责是管理执行任务的线程的中断控制状态,并处理一些附带
 * 的简单记录任务。Worker类继承了AbstractQueuedSynchronizer来简化针对
 * 每个任务执行锁的获取和释放。这样可以防止那些本来意图唤醒正在等待任务的
 * 工作线程的中断信号,错误的中断了正在执行的任务。我们并未使用ReentrantLock
 * 而是自己实现了一个简单的非重入互斥锁,因为我们不想工作线程在调用线程池控制
 * 方法(例如 setCorePoolSize)的时候可以能够重新获取锁(这一句不是太理解,自己找了
 * 一下,发现工作线程需要调用线程池控制方法的情况,只有在工作线程被意外终结,
 * 执行processWorkerExit时,可能会 工作线程数减1,从线程集合中移除当前工作线程,
 * 或者添加新的工作线程,也有可能调用tryTerminate尝试终结掉线程池)。
 * 另外,为了抑制工作线程在开始执行任务之前对中断信号做出响应(suppress interrupts
 * 这里的意思其实是不理会中断信号),我们通常会将锁状态初始化为一个负数,线程一启动
 * 就将负数清楚(runWorker中会获取Worker对象的锁,就会将锁状态修改为1)。
 */
    private final class Worker extends AbstractQueuedSynchronizer
        implements Runnable {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** 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) {
            //抑制中断直到 执行 runWorker
            //先将 state 设置为 -1,防止runWorker之前,中断信号对
            //当前Worker实例的影响
            setState(-1); // inhibit interrupts until runWorker
            //如果firstTask不为空,该工作线程启动时会优先执行firstTask
            this.firstTask = firstTask;
        //由于Runnable对象不能单独启动执行,需要借助一个Thread对象启动才能被执行
        //当前的创建的Worker对象只是一个Runnable对象,需要将其封装到一个Thread实例
        //中,才能借助Thread的run()方法,执行Worker对象的run() 方法
        //这里的this就是指向当前创建的Worker对象
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            // 由于this对象已经被当作一个Runnable对象封装到 this.thread 
            // 对象的target属性,当调用 this.thread 通过start启动时,当前对象
            // 的run()方法就会被调用,这样就会调用到 runWorker(this),runWorker()
            // 就会循环从任务队列获取任务,然后执行
            runWorker(this);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }
        
        // 通过AbstractQueuedSynchronizer尝试获取当前 Worker 对象的锁
        // 由于其继承了AbstractQueuedSynchronizer,一般都需要重写tryAcquire
        // AbstractQueuedSynchronizer默认的实现是throw new         
        // UnsupportedOperationException();
        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // 释放当前 Worker 对象的锁        
        // 由于其继承了AbstractQueuedSynchronizer,一般都需要重写tryRelease
        // AbstractQueuedSynchronizer默认的实现是throw new         
        // UnsupportedOperationException();
        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

七、这里讲解一下Thread.interrupt() 方便理解下面的interruptIdleWorkers()

在Java中,中断(Interrupting)一个线程是一个常用的机制,用于通知线程应该停止
其当前的工作并退出。当你调用一个线程的interrupt()方法时,该线程的中断状态会被
设置为true。然而,线程如何响应这个中断取决于它当前的状态和它正在执行的操作。
详细解析几种不同情况下线程如何响应中断:

If this thread is blocked in an invocation of the Object#wait() , 
Object#wait(long),or Object#wait(long, int) methods of the Object class, 
or of the #join(), #join(long), #join(long, int), #sleep(long), or 
#sleep(long, int)},methods of this class, then its interrupt status will 
be cleared and it will receive an InterruptedException.
如果线程在调用Object类的wait(), wait(long), 或 wait(long, int)方法时被阻塞,
或者调用Thread类的join(), join(long), join(long, int), sleep(long), 
或 sleep(long, int)方法时被阻塞,那么线程的中断状态将被清除,并且线程将接收
到一个InterruptedException异常。这允许线程有机会捕获这个异常并适当地响应中断,
比如清理资源后退出。

除了上面的方法还可以通过java.util.concurrent.locks.Condition的一些方法实现
阻塞,await(),awaitNanos(long nanosTimeout),await(long time, TimeUnit unit)
awaitUntil(Date deadline)等等方法,中断状态被清除的时候,调用被阻塞线程的
interrupt()方法的时候,被阻塞的地方也会接收到InterruptedException异常


If this thread is blocked in an I/O operation upon an 
java.nio.channels.InterruptibleChannel InterruptibleChannel then the 
channel will be closed, the thread's interrupt status will be set, 
and the thread will receive a java.nio.channels.ClosedByInterruptException.
如果线程在一个java.nio.channels.InterruptibleChannel上执行I/O操作时被阻塞,
那么该通道将被关闭,线程的中断状态将被设置,并且线程将接收到一个java.nio.channels.ClosedByInterruptException异常。这种机制允许线程立即响应中断,
并且由于通道被关闭,后续的操作将无法进行。


If this thread is blocked in a java.nio.channels.Selector then the thread's 
interrupt status will be set and it will return immediately from the 
selection operation, possibly with a non-zero value, just as if the 
selector's java.nio.channels.Selector#wakeup wakeup method were invoked.
如果线程在java.nio.channels.Selector上进行选择操作时被阻塞,那么线程的中断状态将
被设置,并且它将立即从选择操作中返回,可能伴随着一个非零值,就像调用了选择器的wakeup()
方法一样。这允许线程响应中断并处理可能的未完成操作

/**
* 以下时java.util.concurrent.ArrayBlockingQueue#take
* 的实现,notEmpty 是一个Condition对象,
* 可以看到ArrayBlockingQueue#take是通过Condition来实现
* 阻塞的,所以当被阻塞线程调用 interrupt()方法的时候,也会
* 抛出 InterruptedException 异常
*
*/
public E take() throws InterruptedException {
   final ReentrantLock lock = this.lock;
   ock.lockInterruptibly();
   try {

        while (count == 0){
           notEmpty.await();
        }

        return dequeue();

   } finally {
       lock.unlock();
   }
}

@Test
public void startInterrupt(){

    final BlockingQueue blockingQueue = new LinkedBlockingQueue();

    final Thread thread = new Thread(){
        @Override
        public void run() {
            boolean flag = true;
            while (flag){
                try {
                    System.out.println("被阻塞了");
                    Object take = blockingQueue.take();
                } catch (Exception e) {
                    e.printStackTrace();
                    flag = false;
                    System.out.println("终端异常被catch");
                }
            }

        }
    };
    thread.start();


    Thread thread1 = new Thread(){
        @Override
        public void run() {

            try {
                TimeUnit.SECONDS.sleep(8);
                thread.interrupt();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };
    thread1.start();


    try {
        TimeUnit.SECONDS.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

 运行结果:

被阻塞了
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
中断异常被catch
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at com.fll.test.thread_pool.ThreadPoolTest$3.run(ThreadPoolTest.java:112)


可以看到 thread 刚开始一直被阻塞到Object take = blockingQueue.take();
直到 thread1 调用 thread.interrupt(); thread 被阻塞的地方抛出InterruptedException

@Test
public void interruptWait() throws InterruptedException {

    final Object lock = new Object();

    final Thread thread = new Thread(){
        @Override
        public void run() {

            String name = Thread.currentThread().getName();

            System.out.println(name + ":开始阻塞");

            synchronized (lock){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(name + ":结束阻塞");
        }
    };



    thread.start();

    Thread.sleep(1000);
    System.out.println("打断 " + thread.getName());

    thread.interrupt();

}

运行结果:
Thread-0:开始阻塞
打断 Thread-0
java.lang.InterruptedException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
Thread-0:结束阻塞
	at com.fll.test.thread_pool.ThreadPoolTest$11.run(ThreadPoolTest.java:492)



@Test
public void interruptJoin() throws InterruptedException {

    final Thread thread = new Thread(){
        @Override
        public void run() {

            String name = Thread.currentThread().getName();

            System.out.println(name + ":开始阻塞");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(name + ":结束阻塞");
        }
    };

    final Thread thread1 = new Thread(){
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            try {
                System.out.println(name + " 开始等待 " + thread.getName() + " 结束");
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };

    thread.start();
    thread1.start();

    Thread.sleep(1);
    System.out.println("打断 " + thread1.getName());
    thread1.interrupt();

    Thread.sleep(1000);

}

运行结果:

Thread-0:开始阻塞
Thread-1 开始等待 Thread-0 结束
打断 Thread-1
java.lang.InterruptedException
	at java.lang.Object.wait(Native Method)
	at java.lang.Thread.join(Thread.java:1252)
	at java.lang.Thread.join(Thread.java:1326)
	at com.fll.test.thread_pool.ThreadPoolTest$10.run(ThreadPoolTest.java:454)
Thread-0:结束阻塞

八、关键方法的解析

/**
 * Executes the given task sometime in the future.  The task
 * may execute in a new thread or in an existing pooled thread.
 * 执行通过参数给定的任务,有时候可能在未来的某一时刻执行。任务可能在
 * 一个新的线程中执行,也可能在被已经存在于线程池中的线程执行。这里
 * 线程池的意思就是工作线程集合private final HashSet<Worker> workers 
 * = new HashSet<Worker>();
 *
 * 
 * If the task cannot be submitted for execution, either because this
 * executor has been shutdown or because its capacity has been reached,
 * the task is handled by the current RejectedExecutionHandler.
 * 如果由于当前线程池已经关闭,或者已经到达它的容量极限,导致任务不能被提交
 * 执行,那么提交的任务会被当前的RejectedExecutionHandler 处理
 * 
 *
 * @param command the task to execute
 * @throws RejectedExecutionException at discretion of
 *         {@code RejectedExecutionHandler}, if the task
 *         cannot be accepted for execution
 * @throws NullPointerException if {@code command} is null
 */
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     * 如果存活的工作线程比corePoolSize少,尝试创建一个新的工作线程,并将
     * 提交的任务command作为新线程的firstTask(新创建的工作线程Worker启动后
     * ,先执行firstTask,然后再从任务队列获取任务执行)。
     * 调用方法addWorker()会自动检测运行状态(runState)和工作线程数(workerCount)
     * ,阻止在不应该添加工作线程的情况下添加了,通过返回false来阻止这种“误报”,
     * 告诉调用addWorker()的调用方,不需要(也不应该)继续尝试添加新线程
     * 
     * 
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     * 如果任务被成功的放入任务队列,我们任然需要再次检查,是否需要
     * 添加一个工作线程,(因为有可能上次检查完之后已经存在的线程都死掉了,
     * 或者自从进入这个方法之后,线程池关闭了)。所以我们再次检查线程池的
     * 状态,如果线程池已经停之了,我们需要将刚刚加入任务队列的任务从队列
     * 中移除掉,或者如果没有存活的可以执行的任务,就创建一个新的线程

     * 当线程池接收到一个新任务时,如果当前没有足够的空闲线程来立即执行该任务,
     * 线程池通常会尝试将该任务放入工作队列中等待执行。然而,仅仅因为任务被成
     * 功排队并不意味着线程池的工作就完成了。线程池还需要考虑以下几点:

     * 线程死亡:自上次检查以来,可能有一些线程因为执行完任务或因为其他原因
     * (如异常)而死亡。这意味着线程池现在可能没有足够的线程来处理队列中的任务。
     * 因此,线程池在将任务排队后应该重新检查线程数量,并在必要时添加新线程。

     * 线程池状态变化:线程池的状态可能在任务排队期间发生变化。例如,
     * 它可能从RUNNING状态转变为SHUTDOWN或STOP状态。如果线程池已经关闭,
     * 那么正在排队的任务可能需要被取消或拒绝,而不是继续等待执行。

     * 为了处理这些情况,线程池在将任务排队后通常会执行以下步骤:

     * 重新检查状态:确认线程池是否仍然处于可以接收新任务的状态(如RUNNING)。
     * 回滚排队:如果发现线程池已经停止(如SHUTDOWN且队列已满,或STOP),
     * 则可能需要将刚刚排队的任务从队列中移除,并可能返回给调用者一个错误或异常。
     * 添加新线程:如果线程池仍然处于运行状态,并且当前线程数量少于maximumPoolSize,
     * 同时工作队列中有等待的任务,那么线程池会尝试添加一个新线程来执行任务。
     * 
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     * 如果新提交的任务添加入任务队列失败,我们得尝试添加一个新的工作线程(
     * 这里是想将入队失败的任务当作新创建的工作线程的firstTask),如果创建新工作
     * 线程失败了(可能是线程池的状态已经关闭,或者工作线程饱和了,也就是工作线程数
     * 达到了maximumPoolSize),我们就得拒绝掉新提交的任务
     * 
     */
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        // 如果工作线程数小于corePoolSize,直接创建一个新的线程
        // true 表示只有在工作线程数小于corePoolSize的情况下才会创建新线程
        // 表示创建的是核心线程
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }

    // 执行到这里有三种情况:
    // 1.状态已经关闭
    // 2.大于等于corePoolSize
    // 3.系统资源不足启动线程失败

    // 没有添加新线程执行新提交的任务,就会尝试将新任务添加到任务队列

    
    if (isRunning(c) && workQueue.offer(command)) {
        
//把新任务添加到任务队列成功,开始重新检查状态和工作线程数
        int recheck = ctl.get();
//如果状态停止了,将入队的任务从队列移除(roll back the enqueuing if stopped)
        if (! isRunning(recheck) && remove(command)){
            //成功移除以后,将任务交给RejectedExecutionHandler处理
            //表示停止以后,不再接受新任务
            reject(command);

//如果未停止,或者移除失败了,检查有没有存活线程执行任务队列的任务
        }else if (workerCountOf(recheck) == 0){
//如果没有存活线程(执行任务时线程可能意外终结),添加新线程,执行任务队列中任务
//false 表示 只要小于maximumPoolSize,就添加
            addWorker(null, false);
        }

//如果停止或者入队失败了(队列满了),尝试添加一个新线程,把入队失败的任务当作
//新线程的firstTask
//两种情况:
//1.停止了,那么addWorker(command, false)必定返回false,直接reject
//表示停止了以后不接受新任务
//2.入队失败了,addWorker(command, false) 可能失败可能成功,如果成功说明
//创建了一个新线程执行入队失败的任务,如果失败表示入队失败任务无法被执行,reject
    }else if (!addWorker(command, false)){
//如果停止或者入队失败了 并且 创建新线程失败,说明新提交的任务无法被执行
//所以将任务交给RejectedExecutionHandler处理
        reject(command);
    }
}
    /**
     * Checks if a new worker can be added with respect to current
     * pool state and the given bound (either core or maximum). If so,
     * the worker count is adjusted accordingly, and, if possible, a
     * new worker is created and started, running firstTask as its
     * first task. This method returns false if the pool is stopped or
     * eligible to shut down. It also returns false if the thread
     * factory fails to create a thread when asked.  If the thread
     * creation fails, either due to the thread factory returning
     * null, or due to an exception (typically OutOfMemoryError in
     * Thread.start()), we roll back cleanly.
     * 根据线程池当前的状态和工作线程数的界限(either core or maximum),
     * 检查是否可以添加一个工作线程。如果可以添加,一个新的工作线程就会被
     * 创建并启动,将firstTask作为新创建工作线程第一个执行的任务。如果当前
     * 线程池已经停止或者符合关闭的条件,那么这个方法就返回false。如果申请
     * 线程工厂创建新线程(threadFactory.newThread())失败,也会返回false。
     * 
     * 如果添加新线程失败是由于threadFactory.newThread()返回null(创建
     * Worker对象的时候构造方法会调用threadFactory.newThread()),或者是
     * 因为一个异常(最典型的就是Thread.start()的时候抛出OutOfMemoryError)。
     * 那么需要回滚清理,这里的回滚清理包含两个意思
     * 1.将提前加上的工作线程数减掉
     * 2.将新添加到Worker集合的worker移除掉
     * 
     * 
     * @param firstTask the task the new thread should run first (or
     * null if none). Workers are created with an initial first task
     * (in method execute()) to bypass queuing when there are fewer
     * than corePoolSize threads (in which case we always start one),
     * or when the queue is full (in which case we must bypass queue).
     * Initially idle threads are usually created via
     * prestartCoreThread or to replace other dying workers.
     * 
     * firstTask是新创建的线程因该首先执行的任务,如果没有就是null。当工作线程数
     * 小于corePoolSize的时候,在execute()方法中创建的Worker会初始化一个
     * firstTask,来避开排队。
     * 初始化空闲线程通常是通过prestartCoreThread或者替换其他死掉的线程
     * 
     * @param core if true use corePoolSize as bound, else
     * maximumPoolSize. (A boolean indicator is used here rather than a
     * value to ensure reads of fresh values after checking other pool
     * state).
     * @return true if successful
     */
    private boolean addWorker(Runnable firstTask, boolean core) {

        retry:
        for (;;) {

            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
//这里会返回false的情况有:
//1.rs > SHUTDOWN,因为STOP的时候,不接受新任务,不处理队列中的任务,不需要添加线程
//2.rs == SHUTDOWN,firstTask != null 因为STOP的时候,不接受新任务,只处理任务队列
//中的堆积任务,firstTask != null 表示有新任务提交,所以直接结束。firstTask == null
//是在线程意外结束,添加一个替换线程时使用
//3.rs == SHUTDOWN  workQueue.isEmpty()==true 表示当队列中没有堆积的任务需要处理
//所以不需要添加新线程了
                return false;

//执行到这里两种情况
//1. rs == RUNNING
//2. rs == SHUTDOWN  firstTask == null  workQueue不为空,
//一种情况发生在runWorker()中线程意外终结,processWorkerExit处理退出时,
//判断如果时意外退出,需要添加一个新的工作线程,替换意外退出的线程 或者 正常退出,
//但是当前线程数小于根据当前配置应该稳定保持的最小空闲线程数
//int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//添加新线程。但是如果allowCoreThreadTimeOut==true,最空闲小线程数min==0,
//这时候需要判断任务队列是否为空,如果不为空,那么至少有一个线程,
//执行队列中任务,min==1,如果线程数为0,则需要添加一个线程

//另一种情况在execute()中,如果新任务成功添加到工作队列但是,工作线程数等于0,
//这是需要添加一个新线程


            //里面这个循环的目的就是将工作线程是加1
            //如果当前工作线程数已经达到了core 情况下的界限值,就返回false
            for (;;) {

                int wc = workerCountOf(c);

                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize)){
                    return false;
                }

//到了这里说明 从状态判断 和 从线程数判断都需要添加一个新线程
//尝试把线程数加1
                if (compareAndIncrementWorkerCount(c)){
//如果加1成功,跳出外面循环,开始执行真正往工作线程集合中添加工作线程的相关操作
                    break retry;
                }

//如果加1失败,重新拉取最新的状态和线程数,说明上面校验完之后,线程数又发生了
//变化
                c = ctl.get();  // Re-read ctl

//如果状态发生了变化,continue外层循环,重新校验状态和线程数是否需要添加新线程
                if (runStateOf(c) != rs){
                    continue retry;
                }

//如果状态没有变化,只需要continue内层循环,重新校验线程数就可以了,直到加1成功
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        //默认启动失败
        boolean workerStarted = false;
        //默认添加失败
        boolean workerAdded = false;
        Worker w = null;
        try {
//创建要添加的新工作线程
            w = new Worker(firstTask);
//Worker的构造方法会默认调用getThreadFactory().newThread()创造一个线程对象
//如果创建失败这里 t = w.thread == null
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
//获取到 总锁之后 重新校验
//如果ThreadFactory失败或在获得锁之前线程池已关闭,则退出
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {

//如果t.isAlive()==true,说明该线程已经调用过 start() 方法了
                        if (t.isAlive()){ // precheck that t is startable
                            throw new IllegalThreadStateException();
                        }

//所有校验都通过了,把新创建的线程添加到集合
                        workers.add(w);

                        int s = workers.size();
//记录最大的集合size
                        if (s > largestPoolSize){
                            largestPoolSize = s;
                        }
                        
                        //标记添加工作线程成功
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }

                //如果成功添加,就需要把添加的线程启动
                if (workerAdded) {
                    t.start();

                    //标记新添加工作线程启动成功
                    workerStarted = true;
                }

            }
        } finally {

//检查是否启动成功,因为启动线程的时候需要申请系统资源,如果没有足够的
//资源,就会启动失败
            if (! workerStarted){

//如果启动失败,需要回滚之前的操作 1.把添加的线程移除 2.把之前加1的线程数减1
                addWorkerFailed(w);
            }

        }

        return workerStarted;
    }
/**
     * Performs blocking or timed wait for a task, depending on
     * current configuration settings, or returns null if this worker
     * must exit because of any of:
     * 根据当前配置,执行阻塞获取任务或者定时获取任务(超过配置的超时时间
     * 就算定时获取任务失败,返回null),
     * 如果当前调用getTask()获取任务的Worker由于下面的原因必须退出,那么
     * getTask() 就返回null
     * getTask()返回null就会导致runWorker()方法中的while循环跳出,之后
     * runWorker()返回,然后线程的run()方法返回,这样该工作线程就结束了
     * 
     * 1. There are more than maximumPoolSize workers (due to
     *    a call to setMaximumPoolSize).
     * 由于通过setMaximumPoolSize修改maximumPoolSize,导致当前工作线程数
     * 大于maximumPoolSize
     * 
     * 2. The pool is stopped.
     * 线程池状态为 STOP
     * 
     * 3. The pool is shutdown and the queue is empty.
     * 线程池状态为SHUTDOWN,并且任务队列为空
     * 
     * 4. This worker timed out waiting for a task, and timed-out
     *    workers are subject to termination (that is,
     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
     *    both before and after the timed wait, and if the queue is
     *    non-empty, this worker is not the last thread in the pool.

     * 工作线程超时:当工作线程在等待新任务时,如果超过了配置的空闲线程存活时间 
     *(keepAliveTime),则该工作线程会超时,这里的工作线程超时意思就是该工作
     * 线程从任务队列获取任务超时,返回null,导致线程结束。这意味着线程没有在
     * 执行任务,而是处于空闲状态的时间过长。

     * 当前线程终止条件:超时的工作线程是否会被终止取决于一下两个条件之一是否满足:
     * 1. allowCoreThreadTimeOut 为 true:这允许核心线程(即线程池中的基本线程数量,
     * 由 corePoolSize 定义)在等待任务时超时并被终止,默认情况下,这个选项是 false,
     * 意味着核心线程即使在空闲时也不会因为超时而被终止。
     * 2. workerCount > corePoolSize:线程池中当前工作线程的数量超过了核心线程数量,
     * 在这种情况下,超出核心线程数量的那些线程(即非核心线程)在等待任务时超时是
     * 可以被终止的。
     * 获取任务超时是必要条件,如果没有超时即使满足上面的两个条件也不会返回null,
     * 导致线程终止

     * 检查时机:这两个条件(是否允许核心线程超时以及工作线程数量是否超过核心线程数量)
     * 会在超时等待之前和之后都被检查。这是为了确保在超时事件发生时,线程池的配置和状态
     * 是最新的,从而做出正确的终止决策。
     * 这里之前和之后检查两次意思是,第一次循环因为默认timedOut==false,不管两条件如何
     * (timed && timedOut) == false,那么第一次循环肯定不会返回null,如果第一次获取
     * 任务超时timedOut==true,第二次循环如果上述两个条件满足一个timed==true,
     * (timed && timedOut) == true,就有可能返回null

     * 任务队列非空且非最后一个线程:如果任务队列(即等待执行的任务队列)不是空的,
     * 并且当前考虑终止的工作线程是线程池中的最后一个线程,那么即使该线程超时了,
     * 也可能不会被立即终止。这是因为线程池通常希望保持至少一个线程活跃,以便能够迅
     * 速响应新任务,特别是当有新任务加入任务队列时。然而,这个条件通常不是决定是否
     * 终止超时工作线程的唯一因素,它更多地是与线程池的整体策略和配置相关的。
     * (timed && timedOut)==true包含两个意思1.超时了2.根据当前配置和线程数量判断需要
     * 减少线程: allowCoreThreadTimeOut==true 或者 wc > corePoolSize
     * 在需要减少线程的前提下通过(wc > 1 || workQueue.isEmpty()) 最终决定要不要减少
     * 这里可以看出如果wc>1,直接就开始尝试减少,只有等于wc==1时才会考虑任务队列是不是为
     * 空,记住如果(timed && timedOut)==false,根本就不会考虑
     * (wc > 1 || workQueue.isEmpty())
     * 
     * 
     * @return task, or null if the worker must exit, in which case
     *         workerCount is decremented
     */
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            
            // Check if queue empty only if necessary.
            // 只在必要的情况下才会校验任务队列是否为空
            if (
                rs >= SHUTDOWN //如果状态>=SHUTDOWN,才会判断后面的逻辑
                && 
//如果状态>=SHUTDOWN,直接返回null,当前线程终结,不会检查队列是否为空
                (rs >= STOP ||  
//执行到这里说明 rs==SHUTDOWN 需要检查队列是否为空,为空才会终结线程
                workQueue.isEmpty())) {

//线程终结之前,提前把工作线程数减1 ,这里属于正常结束
//processWorkerExit(completedAbruptly==false) 就不用减1了
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
//这里其实是在计算,如果不考虑是否超时,单从当前线程的数量和配置角度来看
//是否可以结束当前线程,如果可以,下面就会使用超时的方法从队列获取任务,如果不可以
//就会用阻塞的方法获取任务,直到队列有任务,
//(allowCoreThreadTimeOut==true表示线程数可以减少到0,wc > corePoolSize表示
//线程数大于 corePoolSize,可以减少到corePoolSize)
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

//因为默认timedOut==false,第一次循环肯定(timed && timedOut)==false,不可能返回null
//只有workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)超时返回null,这时
//timedOut==true第二次循环根据最新的allowCoreThreadTimeOut和corePoolSize 配置
//,判断是否要结束线程
            if ((wc > maximumPoolSize || (timed && timedOut))

//如果上面的逻辑判断了,要结束线程,这里还有最后一个要求,就是如果任务队列不为空
//至少要留一个线程来执行队列中的任务,所以这里wc > 1 直接就返回null,如果wc==1,
//那么还需要判断队列,队列不为空不可以结束这最后一个线程
                && (wc > 1 || workQueue.isEmpty())) {

//线程结束前需要先将工作线程数减1,这里先尝试一次,如果减1失败,就下次循环
//如果下次循环,配置改变了,或者 wc 改变了 ,或者队列又加入新任务了可能就
//不需要返回null,我猜这就是这里不用decrementWorkerCount()的原因
                if (compareAndDecrementWorkerCount(c)){
                    return null;
                }

                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
//当前线程被阻塞到 workQueue.take() ,收到 interrupt() 中断信号清除时,会抛出
//InterruptedException,通过catch这个异常,可以解除之前被阻塞的状态,重新开始循环
//从队列中获取任务
                timedOut = false;
            }
        }
    }

 这里聊聊清楚线程的中断状态意义( thread.interrupted() ):

        1.先说说将线程标记为中断(  thread.interrupt() )的意义
        中断状态是线程间协作的一种方式。当一个线程中断了另一个线程时,它实际上是在请求该线程停止其当前的工作。被中断的线程可以明确地知道它已经收到了中断请求,并且应该尽快地处理这个请求(比如通过退出循环、释放资源等)。这有助于促进线程间的协作和程序的整体健壮性。可以通过清除中断状态 ,也就是thread.interrupted() 判断当前线程的是否中断 ,也可以通过thread.isInterrupted()来判断 ,如果使用 thread.interrupted() 来判断是否中断,并且确定已经是中断状态的情况下,没有立即释放资源,并且准备退出,那因该是之前的中断操作已经成功处理掉了,并且不希望线程退出,因为thread.interrupted()在判断的同时会将中断清除,重新改为未中断

        2.除了主动通过 thread.interrupted() 和 thread.isInterrupted() 来判断是否中断,还可以通过捕获异常java.lang.InterruptedException来获取中断事件,在捕获之后进行资源的释放,退出线程等,也可以在捕获之后执行自定义的处理逻辑后,不结束线程,重新将线程标记为未中断( thread.interrupted() )。

        第1点主要说的是象征性的意义,表明有其他线程希望被中断的线程停止其当前的工作,需要主动判断,thread.isInterrupted() 可以多次判断,随时获取当前线程的中断状态,thread.interrupted() 只能判断一次,因为执行一次 thread.interrupted() 之后会将中断清除,修改为未中断,连续两次调用可能返回的结果不一样,这里清除中断状态的意义是,防止在之后某处代码,因为判断线程已经处于中断状态,而选择结束线程。

        第2点主要是在线成遇到阻塞的时候,如果收到中断信号,抛出InterruptedException来,被动通过捕获该异常来知道线程收到了中断信号,可以选择在 catch 块中直接释放资源并结束线程。也可以选择不结束,继续执行,抛出InterruptedException会自动清除中断状态的。下面的代码证明抛出InterruptedException会自动清除中断状态:

  @Test
  public void interruptedExceptionAutoClearInterruptedStatus() {

    final BlockingQueue blockingQueue = new LinkedBlockingQueue();

    final Thread thread = new Thread(){
        @Override
        public void run() {
            try {
                Object take = blockingQueue.take();
            } catch (InterruptedException e) {

                e.printStackTrace();
                //打印验证抛出InterruptedException自动清除中断状态
                System.out.println(Thread.currentThread().getName()+ 
                        "--2: "+Thread.currentThread().isInterrupted());

                //将子线程重新标记为中断状态,验证外部线程可以感知到子线程
                //内部对中断状态的修改
                Thread.currentThread().interrupt();
                System.out.println(Thread.currentThread().getName() + 
                        "--3: "+Thread.currentThread().isInterrupted());

            }

            for (long i = 0; i < 1000000000 ; i++) {
                //这里空转防止子线程结束掉,影响 4 处获取的结果,
                //如果4处获取的时候 子线程 已经结束,获取的结果就不准了
                //提醒这里不可以 sleep ,因为在中断状态下sleep会抛出
                //InterruptedException,并且自动清除中断状态
                //影响 4 处获取的结果
            }

            System.out.println("先完成子线程");

        }
    };


    thread.start();

    thread.interrupt();

    //先打印子线程中断后的 中断状态
    System.out.println(thread.getName() + "--1: " + thread.isInterrupted());


    try {
        //这里主线程等一下,防止 4 处获取的时候,子线程的代码还没执行
        TimeUnit.MILLISECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("先获取子线程内是否成功将自动清除的中断状态,再次修改为 已中断");
    //子线程未执行完之前,重新获取子线程的中断状态,验证外部线程可以感知到子线程
    //内部对中断状态的修改
    System.out.println(thread.getName() + "--4: " + thread.isInterrupted());

    try {
        //这里稍微等一下子线程空转完了之后,父线程再结束
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

 运行结果:

java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:439)
	at com.fll.test.thread_pool.ThreadPoolTest$8.run(ThreadPoolTest.java:317)
Thread-0--1: true
Thread-0--2: false
Thread-0--3: true
先获取子线程内是否成功将自动清除的中断状态,再次修改为 已中断
Thread-0--4: true
先完成子线程

1处打印true,表示子线程此时处于中断状态
2处打印false,表示子线程抛出InterruptedException之后中断状态自动清除
3处打印true,表示子线程成功将自己重新标记为中断状态
4处打印true,表示子线程将自己重新标记为中断状态之后,外部线程可以感知到

如果一个线程处于中断状态,那么遇到以下情况会报错

        1.在中断的线程中调用以下方法:
                java.util.concurrent.locks.Condition#await() , java.util.concurrent.BlockingQueue#take
                ,java.lang.Thread#sleep(long, int) ,                              java.util.concurrent.locks.ReentrantLock#lockInterruptibly                                        
                等方法会抛出java.lang.InterruptedException

@Test
public void exceptionOnInterruptStatus() {

    Thread.currentThread().interrupt();

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

运行结果:
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.fll.test.thread_pool.ThreadPoolTest.exceptionOnInterruptStatus(ThreadPoolTest.java:

@Test
public void exceptionOnInterruptStatus() {

    final BlockingQueue blockingQueue = new LinkedBlockingQueue();

    Thread.currentThread().interrupt();
    try {
        blockingQueue.take();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

运行结果:

java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:439)
	at com.fll.test.thread_pool.ThreadPoolTest.exceptionOnInterruptStatus(ThreadPoolTest.java:385)


@Test
public void exceptionOnInterruptStatus() {

    final BlockingQueue blockingQueue = new LinkedBlockingQueue();

    ReentrantLock lock = new ReentrantLock();

    Thread.currentThread().interrupt();

    try {

        lock.lockInterruptibly();
		
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

运行结果:
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at com.fll.test.thread_pool.ThreadPoolTest.exceptionOnInterruptStatus(ThreadPoolTest.java:398)


@Test
public void exceptionOnInterruptStatus() throws InterruptedException {

    ReentrantLock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

	Thread.currentThread().interrupt();

	try {
		condition.await();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}

}

运行结果:
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2034)
	at com.fll.test.thread_pool.ThreadPoolTest.exceptionOnInterruptStatus(ThreadPoolTest.java:391)

        2.在中断的线程中调用以下方法:
      
 java.lang.Object#wait(),java.lang.Object#wait(long) ,java.lang.Object#wait(long, int) 等方法会抛出 java.lang.InterruptedException,这里需要记住,wait() 方法必须在 synchronized 代码
​​​​​​​块内调用,并且必须调用 synchronized 选择的监视器对象的 wait() 方法,否则要抛出非法监视器的异常 java.lang.IllegalMonitorStateException

@Test
public void exceptionOnInterruptStatusWait() {


    Object lock = new Object();

    Thread.currentThread().interrupt();

    synchronized (lock) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

运行结果:

java.lang.InterruptedException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at com.fll.test.thread_pool.ThreadPoolTest.exceptionOnInterruptStatusWait(ThreadPoolTest.java:418)

综合考虑情况,如果抛出​​​​​​​ InterruptedException 不自动清除线程的中断状态,如果该异常被catch掉之后,没有选择结束线程,那么在后面的业务代码中遇到上面的这些方法就会自动抛出异常,有可能会影响到最终结果,还有我们在自己的代码中如果使用java.lang.Thread#isInterrupted()判断当前线程已经处于中断状态,如果选择不结束当前线程,继续执行的话,最好通过java.lang.Thread#interrupted 清除掉中断状态,否则也会有相同的情况

做个总结:线程被中断只是表明其他线程希望该线程结束,但是并不能直接决定它结束,具体结不结束,得由被中断的线程自己决定,它在获取到中断的信息以后(主动查询 ,被动通过异常得知),
​​​​​​​可以选择继续执行,也可以选择释放资源,结束线程

/**
 * Main worker run loop.  Repeatedly gets tasks from queue and
 * executes them, while coping with a number of issues:
 * 工作线程的主循环,不断的从任务队列获取任务然后执行,同时还得处理
 * 一些问题
 * 
 *
 * 1. We may start out with an initial task, in which case we
 * don't need to get the first one. Otherwise, as long as pool is
 * running, we get tasks from getTask. If it returns null then the
 * worker exits due to changed pool state or configuration
 * parameters.  Other exits result from exception throws in
 * external code, in which case completedAbruptly holds, which
 * usually leads processWorkerExit to replace this thread.
 * 我们启动的工作线程可能会带一个初始任务(也就是创建Worker对象的时候
 * 会传一个firstTask),在这种情况下启动后的第一次循环,不需要从任务队列
 * 获取任务。否则只要线程池处于运行状态,就会不停从任务队列获取任务。
 * 如果由于改变线程池的状态或者配置参数导致getTask()返回null,那这个线程
 * 就会退出。如果由于外部代码抛出异常导致线程退出,completedAbruptly==true,
 * 这通常会导致processWorkerExit()方法替换掉该线程,这里替换的意思是,
 * 把该线程移除并终结掉,然后添加一个新的工作线程
 * 
 * 
 * 2. Before running any task, the lock is acquired to prevent
 * other pool interrupts while the task is executing, and then we
 * ensure that unless pool is stopping, this thread does not have
 * its interrupt set.
 * 在任何任务之前,需要先获取当前工作线程的锁,防止正在执行任务的时候
 * 线程池对该工作线程中断信号。interruptIdleWorkers需要判断工作线程
 * 是否空闲只需要尝试获取该工作线程的锁,如果获取成功了,说明线程是空闲的。
 * 如果非空闲线程收到中断信号(shutdownNow),可能会导致运行结果错误,
 * 例如:我们提交的任务中如果被阻塞,也就是我们业务代码中有阻塞。
 * 这时候如果调用工作线程的interrupt()方法就会导致抛出InterruptedException。
 * 如果我们的业务代码中有判断Thread.currentThread().isInterrupted()的,也会
 * 出现判断错误
 * 
 * 
 * 3. Each task run is preceded by a call to beforeExecute, which
 * might throw an exception, in which case we cause thread to die
 * (breaking loop with completedAbruptly true) without processing
 * the task.
 * 每个任务执行之前都会先执行 beforeExecute,执行beforeExecute的时候
 * 可能会抛出异常,这种情况会导致不处理任务,线程直接死掉(跳出循环,
 * 并且调用processWorkerExit()的时候 completedAbruptly==true)。
 * 
 * 4. Assuming beforeExecute completes normally, we run the task,
 * gathering any of its thrown exceptions to send to afterExecute.
 * We separately handle RuntimeException, Error (both of which the
 * specs guarantee that we trap) and arbitrary Throwables.
 * Because we cannot rethrow Throwables within Runnable.run, we
 * wrap them within Errors on the way out (to the thread's
 * UncaughtExceptionHandler).  Any thrown exception also
 * conservatively causes thread to die.
 * 如果beforeExecute顺利执行完,就开始执行任务,收集执行任务抛出的所有
 * 异常,传给 afterExecute().RuntimeException、Error 、Throwables
 * 是分开处理的,
 * 
 * 
 * 5. After task.run completes, we call afterExecute, which may
 * also throw an exception, which will also cause thread to
 * die. According to JLS Sec 14.20, this exception is the one that
 * will be in effect even if task.run throws.
 * 
 * 
 * 
 * 
 * The net effect of the exception mechanics is that afterExecute
 * and the thread's UncaughtExceptionHandler have as accurate
 * information as we can provide about any problems encountered by
 * user code.
 *
 * 
 * 
 * 
 * @param w the worker
 */
final void runWorker(Worker w) {

    Thread wt = Thread.currentThread();

    Runnable task = w.firstTask;
    w.firstTask = null;

    w.unlock(); // allow interrupts

    //默认线程异常退出
    boolean completedAbruptly = true;

    try {
        while (task != null || (task = getTask()) != null) {

            //获取到将要执行的任务,先获取锁,防止在执行任务的时候收到中断
            //信号,影响到任务中正常业务需要的阻塞被中断
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted. This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
// 这里的注释翻译意思是
// 如果线程池已经开启停止,要确保线程最终都中断
// 如果线程池没有开启停止,也就是(second case), 当清除完中断状态后
// (Thread.interrupted()会清除中断状态) ,需要二次检测线程池的状态
// 来应对shutdownNow的竞争,意思就是,清除中断状态的时候,可能状态被shutdownNow
// 修改为已经开启停止,二次检测状态

//这段逻辑有以下几种情况
// 1.已经开启停止,直接判断当前线程是否中断,如果未中断,就将其中断(不知道有什么具体意义)
// 2.未开启停止,先清除中断状态,如果当前处于中断状态,再判断如果此时变成启动停止,那么
// 需要将其中断,因为中断已经被清除掉了
// 3.未开启停止,先清除中断状态,如果当前处于中断状态,再判断如果此时还未启动停止,不做处理
// 因为中断已经被清除掉了
// 4.未开启停止,先清除中断状态,如果当前不是处于中断状态,不做处理
            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 {
        //这里作为线程退出的善后收尾处理,completedAbruptly==true表示异常退出
        processWorkerExit(w, completedAbruptly);
    }
}
 /**
 * Performs cleanup and bookkeeping for a dying worker. Called
 * only from worker threads. Unless completedAbruptly is set,
 * assumes that workerCount has already been adjusted to account
 * for exit.  This method removes thread from worker set, and
 * possibly terminates the pool or replaces the worker if either
 * it exited due to user task exception or if fewer than
 * corePoolSize workers are running or queue is non-empty but
 * there are no workers.
 * 执行一个即将终结的线程的清楚和计数,该方法只会被工作线程调用
 * 除非completedAbruptly==true(其实就是)
 *
 *
 *
 *
 *
 *
 * @param w the worker
 * @param completedAbruptly if the worker died due to user exception
 */
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//如果是意外退出,说明没有提前线程数减1,这里需要减1
//正常退出是由于getTask()==null 导致循环结束,线程退出,这种情况
//getTask()返回null之前都会提前把工作线程数减1
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        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)) {

//如果线程池当前还未达到STOP状态,需要考虑要不要添加一个
//新线程替代当前退出的线程

        if (!completedAbruptly) {

//如果当前线程是正常退出,需要根据当前线程数和任务队列是否为空
//结合线程池的配置共同决定是否要添加一个替代线程
            
//计算出最小的空闲线程数,正常退出的都是空闲线程
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;

//如果allowCoreThreadTimeOut==true ,最小的空闲线程数 min == 0
//这时就要看任务队列是否有堆积的任务,如果有的话,至少得留一个线程
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;

//如果线程数大于等于当前至少因该保持的线程数,就不需要添加替代线程
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }else{
            //如果当前线程是异常退出直接新添加一个线程,替换当前退出的线程
        }
        addWorker(null, false);
    }
}

/**
 * Interrupts threads that might be waiting for tasks (as
 * indicated by not being locked) so they can check for
 * termination or configuration changes. Ignores
 * SecurityExceptions (in which case some threads may remain
 * uninterrupted).
 * 中断那些正在等待任务的线程(表明他们没有被锁,因为成功获取任务)
 * 开始执行之前,会先获取工作线程的锁),这样他们就可以检测是否可以
 * 终结,或者检测配置是否改变
 *
 * @param onlyOne If true, interrupt at most one worker. This is
 * called only from tryTerminate when termination is otherwise
 * enabled but there are still other workers.  In this case, at
 * most one waiting worker is interrupted to propagate shutdown
 * signals in case all threads are currently waiting.
 * Interrupting any arbitrary thread ensures that newly arriving
 * workers since shutdown began will also eventually exit.
 * To guarantee eventual termination, it suffices to always
 * interrupt only one idle worker, but shutdown() interrupts all
 * idle workers so that redundant workers exit promptly, not
 * waiting for a straggler task to finish.
 * 当onlyOne为true时,该方法在尝试终止过程中,最多只中断一个当前处于等待状态
 * 的工作线程。(有一些操作可能会导致满足terminate的条件,例如:addWorkerFailed , 
 * processWorkerExit , shutdown , shutdownNow , remove , purge), 所以在执
 * 行这些操作的时候,往往会调用tryTerminate(),来检测是否可以终结线程池,
 * interruptIdleWorkers(true) 只会在 tryTerminate() 中确认终止操作已被启动
 * (意思就是除了工作线程数不等于0以外,其他终结的条件都满足了)的情况下才会被调用。
 * 在这种情况下,最多中断一个等待线程来传递关闭信号(这里的传播意思就是如果中断的
 * 这一个线程如果完成了终结操作,修改了状态,其他线程检测到终结状态,就不会再执行
 * 一次),以免当前所有的工作线程都处于等待状态(这里之所以这样说是因为如果当前
 * 线程都处于等待状态,中断多个线程,可能会导致多个线程都判断未完成终结,导致
 * 终结操作被执行多次)。从保证线程池最终能够终止的角度来看,只需要在需要时中断
 * 一个空闲的工作线程就足够了(suffices)。然而,shutdown()方法(通常用于优雅关
 * 闭线程池)会中断所有空闲的工作线程,这样做的目的是为了让那些不再需要的
 * (redundant 多余的)线程能够迅速(promptly)退出,而不是等待某个可能长时间运行
 * 的任务(straggler 落在最后的人)完成,工作线从而加快线程池的关闭过程。
 */
private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
//这里获取锁的原因是,当工作线程获取一个任务准备执行前,会获取工作线程的锁
//直到任务执行完毕,释放锁,所以在任务执行期间,这里是获取不到工作线程的锁的
//这样可以避免掉正在执行任务线程暂时不被终结,保证正在执行的任务能够执行完(
//这样就跟方法名 中断空闲的线程 对应起来),
//也可以避免掉 执行的任务中 如果我们的业务代码有需要阻塞的逻辑,在阻塞期间
//被这里的中断信号影响,会抛出InterruptedException异常,导致最终任务执行
//的结果错误,这种情况导致的结果更加严重
            if (!t.isInterrupted() && w.tryLock()) {
                try {

//这里的中断信号可以使原本阻塞在getTask()中
//Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
//workQueue.take(); 这个地方的工作线程抛出InterruptedException异常,可以通过
//catch这个异常,解除阻塞,进入下一次循环,重新拉取最新的状态 和 配置 以及工作
//线程数,重新判断该线程是不是因该终结,如果需要终结,则返回null,使runWorker()
//的循环结束,最终线程结束

                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}


/**
 * Transitions to TERMINATED state if either (SHUTDOWN and pool
 * and queue empty) or (STOP and pool empty).  If otherwise
 * eligible to terminate but workerCount is nonzero, interrupts an
 * idle worker to ensure that shutdown signals propagate. This
 * method must be called following any action that might make
 * termination possible -- reducing worker count or removing tasks
 * from the queue during shutdown. The method is non-private to
 * allow access from ScheduledThreadPoolExecutor.
 * 在线程池状态为SHUTDOWN并且工作线程集合和任务队列都为空的情况下,或者线程池
 * 为STOP并且工作线程集合为空的情况下,将线程池状态转变TERMINATED。
 * 如果具备terminate的条件,但是workerCount不是0,就中断一个空闲工作线程,确保
 * shutdown的信号传播。任何可能导致termination的操作(在shutdown状态下,减少工作
 * 线程或者从任务队列中移除任务等操作)之后都必须调用该方法。这个方法是非私有的,
 * 容许从ScheduledThreadPoolExecutor中进行访问
 * 
 * 
 */
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (
            isRunning(c) ||
    //如果是RUNNING不可以terminate()
            runStateAtLeast(c, TIDYING) ||
    //状态是TIDYING、或TERMINATED,已经终止过了(因为如果当前状态为TIDYING,
//那么说明有其他线程已经获取了mainLock并且执行ctl.compareAndSet(c,ctlOf(TIDYING,0)))
    //成功了,不管terminated()执行是否异常,ctl.set(ctlOf(TERMINATED, 0))
    //都会执行将runState修改为TERMINATED,这里不需要再terminated()
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
    //如果当前是SHUTDOWN并且任务队列不为空,不满足terminate()条件
            return;

    //执行到这里只有两种情况
    //1.状态为SHUTDOWN,任务队列为空
    //2.状态为STOP
    //这两种情况都是只要满足 工作线程数为0,就满足terminate()的条件


        if (workerCountOf(c) != 0) { // Eligible to terminate
//工作线程数如果不为0,说明不可terminate(),但是只剩工作线程变为0,一个条件了
//这里先中断一个空闲工作线程
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

//执行到这里说明工作线程也已经减少到 0 了,可以终结线程池了
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
//先将线程池的状态修改为TIDYING,这一步其实也有加锁的作用
//因为只有一个线程可以修改成功,并调用 terminated()
//防止多个线程执行 terminated()
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}
/**
 * Attempts to CAS-increment the workerCount field of ctl.
 * 尝试通过cas 将workerCount增加expect.这个方法不管成功或者失败
 * 只会尝试一次.
 * 这里之所以直接对 ctl 进行加expect,是因为 workerCount 保存在
 * ctl 的低29,所以只要 workerCount 不超过29位能表示的最大值
 * 直接对ctl加expect,就相当于 workerCount 加expect
 * 
 */
private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}

/**
 * Attempts to CAS-decrement the workerCount field of ctl.
 * 尝试通过cas 将workerCount减去expect
 */
private boolean compareAndDecrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect - 1);
}

/**
 * Decrements the workerCount field of ctl. This is called only on
 * abrupt termination of a thread (see processWorkerExit). Other
 * decrements are performed within getTask.
 * 通过cas 将workerCount减1,这里不是只尝试一次,而是不断尝试,直到成功
 * 减 1 ,这个方法只有在一个线程突然终结的情况下才会被调用(具体可以看
 * processWorkerExit 这个方法)。其他的减少操作是在 getTask 方法中调用
 * 
 */
private void decrementWorkerCount() {
    do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}


/**
 * Transitions runState to given target, or leaves it alone if
 * already at least the given target.
 * 将线程池的状态转变到给定的值,如果当前的状态已经大于等于给定的
 * 状态就不做处理。其实这里的给定状态只有 SHUTDOWN 或者 STOP
 * @param targetState the desired state, either SHUTDOWN or STOP
 *        (but not TIDYING or TERMINATED -- use tryTerminate for that)
 * 这里的给定状态只有 SHUTDOWN 或者 STOP,不能是 TIDYING 或者 TERMINATED
 * 只能通过 tryTerminate 转换到 TIDYING 或者 TERMINATED 状态
 */
private void advanceRunState(int targetState) {
    for (;;) {
        int c = ctl.get();
        if (
            //判断是否已经大于等于给定的状态
            runStateAtLeast(c, targetState) ||
            // 如果不是大于等于给定状态,就尝试修改为指定的状态
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值