Java多线程与高并发专题——线程池源码剖析

引入

我们先梳理一下如何自定义线程池,首先ThreadPoolExecutor中,一共提供了7个参数,每个参数都是非常核心的属性,在线程池去执行任务时,每个参数都有决定性的作用。

但是如果直接采用JDK提供的方式去构建,可以设置的核心参数最多就两个,这样就会导致对线程池的控制粒度很粗。所以推荐自己去自定义线程池,也就是手动的去new ThreadPoolExecutor 设置他的一些核心属性。自定义构建线程池,可以细粒度的控制线程池,去管理内存的属性,并且针对一些参数的设置可能更好的在后期排查问题。

ThreadPoolExecutor提供的七个核心参数:

public ThreadPoolExecutor(
    int corePoolSize,           // 核心工作线程(当前任务执行结束后,不会被销毁)
    int maximumPoolSize,        // 最大工作线程(代表当前线程池中,一共可以有多少个工作线程)
    long keepAliveTime,         // 非核心工作线程在阻塞队列位置等待的时间
    TimeUnit unit,              // 非核心工作线程在阻塞队列位置等待时间的单位
    BlockingQueue workQueue,   // 任务在没有核心工作线程处理时,任务先扔到阻塞队列中
    ThreadFactory threadFactory,         // 构建线程的线程工作,可以设置thread的一些信息
    RejectedExecutionHandler handler) {  // 当线程池无法处理投递过来的任务时,执行当前的拒绝策略
    // 初始化线程池的操作
}

下面就深入剖析ThreadPoolExecutor的源码:

ThreadPoolExecutor的核心属性

核心属性主要就是ctl,基于ctl拿到线程池的状态以及工作线程个数

在整个线程池的执行流程中,会基于ctl判断上述两个内容

/**
* 主池控制状态,ctl,是一个原子整数,包含两个概念字段
*   workerCount,表示有效线程数
*   runState,表示是否正在运行、关闭等
*
* 为了将它们打包到一个int中,我们将workerCount限制为
* (2^29)-1(约5亿)个线程,而不是(2^31)-1(20亿)个线程。如果将来出现这个问题,
* 可以将变量更改为AtomicLong,并调整下面的移位/掩码常量。但在需要之前,使用int会更快更简单。
*
* workerCount是已被允许启动且不允许停止的工作线程数。该值可能会暂时与实际活动线程数不同,
* 例如,当ThreadFactory在被请求时无法创建线程,以及退出线程在终止前仍在执行簿记操作时。
* 用户可见的池大小报告为工作线程集的当前大小。
*
* runState提供主要的生命周期控制,取值如下:
*
*   RUNNING:接受新任务并处理排队任务
*   SHUTDOWN:不接受新任务,但处理排队任务
*   STOP:不接受新任务,不处理排队任务,并中断正在进行的任务
*   TIDYING:所有任务已终止,workerCount为零,
*            转换到TIDYING状态的线程将运行terminated()钩子方法
*   TERMINATED:terminated()已完成
*
* 这些值之间的数值顺序很重要,以便进行有序比较。runState随时间单调增加,但不一定会经过每个状态。
* 转换过程如下:
*
* RUNNING -> SHUTDOWN
*    在调用shutdown()时,可能在finalize()中隐式调用
* (RUNNING或SHUTDOWN) -> STOP
*    在调用shutdownNow()时
* SHUTDOWN -> TIDYING
*    当队列和池都为空时
* STOP -> TIDYING
*    当池为空时
* TIDYING -> TERMINATED
*    当terminated()钩子方法完成时
*
* 在awaitTermination()中等待的线程将在状态达到TERMINATED时返回。
*
* 检测从SHUTDOWN到TIDYING的转换比你想象的要复杂,因为在SHUTDOWN状态下,队列可能会在非空之后变为空,反之亦然,
* 但只有在看到队列为空后,我们看到workerCount为0时才能终止(这有时需要重新检查——见下文)。
*/
// 当前是线程池的核心属性
// 当前的ctl其实就是一个int类型的数值,内部是基于AtomicInteger套了一层,进行运算时,是原子性的。
// ctl表示着线程池中的2个核心状态:
// 线程池的状态:ctl的高3位,表示线程池状态
// 工作线程的数量:ctl的低29位,表示工作线程的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

// Integer.SIZE:在获取Integer的bit位个数
// 声明了一个常量:COUNT_BITS = 29
private static final int COUNT_BITS = Integer.SIZE - 3;

// CAPACITY就是当前工作线程能记录的工作线程的最大个数
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;


// 线程池状态的表示
// 当前五个状态中,只有RUNNING状态代表线程池没问题,可以正常接收任务处理
// 111:代表RUNNING状态,RUNNING可以处理任务,并且处理阻塞队列中的任务。
private static final int RUNNING    = -1 << COUNT_BITS;
// 000:代表SHUTDOWN状态,不会接收新任务,正在处理的任务正常进行,阻塞队列的任务也会做完。
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 001:代表STOP状态,不会接收新任务,正在处理任务的线程会被中断,阻塞队列的任务一个不管。
private static final int STOP       =  1 << COUNT_BITS;
// 010:代表TIDYING状态,这个状态是否SHUTDOWN或者STOP转换过来的,代表当前线程池马上关闭,就是过渡状态。
private static final int TIDYING    =  2 << COUNT_BITS;
// 011:代表TERMINATED状态,这个状态是TIDYING状态转换过来的,转换过来只需要执行一个terminated方法。
private static final int TERMINATED =  3 << COUNT_BITS;

// 在使用下面这几个方法时,需要传递ctl进来

// 基于&运算的特点,保证只会拿到ctl高三位的值。
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 基于&运算的特点,保证只会拿到ctl低29位的值。
private static int workerCountOf(int c)  { return c & CAPACITY; }

ThreadPoolExecutor的有参构造

有参构造没啥说的,值得注意的就核心线程个数是允许为0的。

/**
* 创建一个新的 {@code ThreadPoolExecutor} 实例,使用给定的初始参数。
*
* @param corePoolSize 线程池中保持的线程数量,即使它们处于空闲状态,除非设置了 {@code allowCoreThreadTimeOut}。
* @param maximumPoolSize 线程池中允许的最大线程数量。
* @param keepAliveTime 当线程数量大于核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
* @param unit 用于 {@code keepAliveTime} 参数的时间单位。
* @param workQueue 用于在执行任务之前保存任务的队列。此队列仅保存由 {@code execute} 方法提交的 {@code Runnable} 任务。
* @param threadFactory 当执行器创建新线程时使用的工厂。
* @param handler 当线程边界和队列容量达到时,执行被阻塞时使用的处理程序。
* @throws IllegalArgumentException 如果以下条件之一成立:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize} * @throws NullPointerException 如果 {@code workQueue}、{@code threadFactory} 或 {@code handler} 为 null。 */ // 有参构造。无论调用哪个有参构造,最终都会执行当前的有参构造 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { // 健壮性校验 // 核心线程个数是允许为0个的。 // 最大线程数必须大于0,最大线程数要大于等于核心线程数 // 非核心线程的最大空闲时间,可以等于0 if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) // 不满足要求就抛出参数异常 throw new IllegalArgumentException(); // 阻塞队列,线程工厂,拒绝策略都不允许为null,为null就扔空指针异常 if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); // 不要关注当前内容,系统资源访问决策,和线程池核心业务关系不大。 this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); // 各种赋值,JUC包下,几乎所有涉及到线程挂起的操作,单位都用纳秒。 // 有参构造的值,都赋值给成员变量。 // Doug Lea的习惯就是将成员变量作为局部变量单独操作。 this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }

ThreadPoolExecutor的execute方法

execute方法是提交任务到线程池的核心方法,很重要

线程池的执行流程其实就是在说execute方法内部做了哪些判断

execute源码的分析

/**
* 执行给定的任务,任务可能在新线程或现有线程池中执行。
* 
* 如果任务无法提交执行,可能是因为执行器已关闭或容量已达上限,
* 此时任务将由当前的{@code RejectedExecutionHandler}处理。
* 
* @param command 要执行的任务
* @throws RejectedExecutionException 如果任务无法被接受执行,由{@code RejectedExecutionHandler}决定是否抛出异常
* @throws NullPointerException 如果{@code command}为null
*/
// 提交任务到线程池的核心方法
// command就是提交过来的任务
public void execute(Runnable command) {
    // 提交的任务不能为null
    if (command == null)
        throw new NullPointerException();
    /*
    * 分三步进行:
    *
    * 1. 如果正在运行的线程数少于核心池大小,尝试以给定的命令作为其第一个任务启动一个新线程。
    *    对addWorker的调用会原子性地检查运行状态和工作线程数,通过返回false来防止在不应该添加线程时发出错误警报。
    *
    * 2. 如果任务能够成功排队,那么我们仍然需要再次检查是否应该添加一个线程(因为自上次检查以来现有线程可能已经死亡),
    *    或者自进入此方法以来池是否已关闭。因此,我们重新检查状态,如果必要,在停止时回滚入队操作,或者在没有线程时启动一个新线程。
    *
    * 3. 如果我们无法排队任务,那么我们尝试添加一个新线程。如果失败,我们知道我们已关闭或饱和,因此拒绝该任务。
    */
    // 获取核心属性ctl,用于后面的判断
    int c = ctl.get();
    // 如果工作线程个数,小于核心线程数。
    // 满足要求,添加核心工作线程
    if (workerCountOf(c) < corePoolSize) {
        // addWorker(任务,是核心线程吗)
        // addWorker返回true:代表添加工作线程成功
        // addWorker返回false:代表添加工作线程失败
        // addWorker中会基于线程池状态,以及工作线程个数做判断,查看能否添加工作线程
        if (addWorker(command, true))
            // 工作线程构建出来了,任务也交给command去处理了。
            return;
        // 说明线程池状态或者是工作线程个数发生了变化,导致添加失败,重新获取一次ctl
        c = ctl.get();
    }
    // 添加核心工作线程失败,往这走
    // 判断线程池状态是否是RUNNING,如果是,正常基于阻塞队列的offer方法,将任务添加到阻塞队列
    if (isRunning(c) && workQueue.offer(command)) {
        // 如果任务添加到阻塞队列成功,走if内部
        // 如果任务在扔到阻塞队列之前,线程池状态突然改变了。
        // 重新获取ctl
        int recheck = ctl.get();
        // 如果线程池的状态不是RUNNING,将任务从阻塞队列移除,
        if (!isRunning(recheck) && remove(command))
            // 并且直接拒绝策略
            reject(command);
        // 在这,说明阻塞队列有我刚刚放进去的任务
        // 查看一下工作线程数是不是0个
        // 如果工作线程为0个,需要添加一个非核心工作线程去处理阻塞队列中的任务
        // 发生这种情况有两种:
        // 1. 构建线程池时,核心线程数是0个。
        // 2. 即便有核心线程,可以设置核心线程也允许超时,设置allowCoreThreadTimeOut为true,代表核心线程也可以超时
        else if (workerCountOf(recheck) == 0)
            // 为了避免阻塞队列中的任务饥饿,添加一个非核心工作线程去处理
            addWorker(null, false);
    }
    // 任务添加到阻塞队列失败
    // 构建一个非核心工作线程
    // 如果添加非核心工作线程成功,直接完事,告辞
    else if (!addWorker(command, false))
        // 添加失败,执行决绝策略
        reject(command);
}

ThreadPoolExecutor的addWorker方法

addWorker中主要分成两大块去看

  • 第一块:校验线程池的状态以及工作线程个数

  • 第二块:添加工作线程并且启动工作线程

校验线程池的状态以及工作线程个数

// 添加工作线程之校验源码
private boolean addWorker(Runnable firstTask, boolean core) {
    // 外层for循环在校验线程池的状态
    // 内层for循环是在校验工作线程的个数

    // retry是给外层for循环添加一个标记,是为了方便在内层for循坏跳出外层for循环
    retry:
    for (;;) {
        // 获取ctl
        int c = ctl.get();
        // 拿到ctl的高3位的值
        int rs = runStateOf(c);
//==========================线程池状态判断==================================================
        // 如果线程池状态是SHUTDOWN,并且此时阻塞队列有任务,工作线程个数为0,添加一个工作线程去处理阻塞队列的任务

        // 判断线程池的状态是否大于等于SHUTDOWN,如果满足,说明线程池不是RUNNING
        if (rs >= SHUTDOWN &&
            // 如果这三个条件都满足,就代表是要添加非核心工作线程去处理阻塞队列任务
            // 如果三个条件有一个没满足,返回false,配合!,就代表不需要添加
            !(rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
            // 不需要添加工作线程
            return false;

        for (;;) {
//==========================工作线程个数判断================================================== 
            // 基于ctl拿到低29位的值,代表当前工作线程个数   
            int wc = workerCountOf(c);
            // 如果工作线程个数大于最大值了,不可以添加了,返回false
            if (wc >= CAPACITY ||
                // 基于core来判断添加的是否是核心工作线程
                // 如果是核心:基于corePoolSize去判断
                // 如果是非核心:基于maximumPoolSize去判断
                wc >= (core ? corePoolSize : maximumPoolSize))
                // 代表不能添加,工作线程个数不满足要求
                return false;
            // 针对ctl进行 + 1,采用CAS的方式
            if (compareAndIncrementWorkerCount(c))
                // CAS成功后,直接退出外层循环,代表可以执行添加工作线程操作了。
                break retry;
            // 重新获取一次ctl的值
            c = ctl.get(); 
            // 判断重新获取到的ctl中,表示的线程池状态跟之前的是否有区别
            // 如果状态不一样,说明有变化,重新的去判断线程池状态
            if (runStateOf(c) != rs)
                // 跳出一次外层for循环
                continue retry;
        }
    }
    // 省略添加工作线程以及启动的过程
}

添加工作线程并且启动工作线程

/**
* 检查是否可以根据当前池状态和给定的边界(核心或最大)添加新的工作线程。如果可以,相应地调整工作线程计数,并且如果可能,创建并启动一个新的工作线程,将 firstTask 作为其第一个任务运行。如果池已停止或有资格关闭,此方法返回 false。如果线程工厂在请求时无法创建线程,它也返回 false。如果线程创建失败,无论是由于线程工厂返回 null,还是由于异常(通常是 Thread.start() 中的 OutOfMemoryError),我们都会干净地回滚。
*
* @param firstTask 新线程应首先运行的任务(如果没有则为 null)。在工作线程少于 corePoolSize 时(在这种情况下我们总是启动一个),或者队列已满(在这种情况下我们必须绕过队列),创建工作线程时会有一个初始的第一个任务(在 execute() 方法中)以绕过排队。最初的空闲线程通常通过 prestartCoreThread 创建或用于替换其他死亡的工作线程。
*
* @param core 如果为 true,则使用 corePoolSize 作为边界,否则使用 maximumPoolSize。(这里使用布尔指示符而不是值,以确保在检查其他池状态后读取最新值)。
* @return 如果成功则为 true
*/
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()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }
    // 添加工作线程以及启动工作线程
    // 声明了三个变量
    // 工作线程启动了没,默认false
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 构建工作线程,并且将任务传递进去
        w = new Worker(firstTask);
        // 获取了Worker中的Thread对象
        final Thread t = w.thread;
        // 判断Thread是否不为null,在new Worker时,内部会通过给予的ThreadFactory去构建Thread交给Worker
        // 一般如果为null,代表ThreadFactory有问题。
        if (t != null) {
            // 加锁,保证使用workers成员变量以及对largestPoolSize赋值时,保证线程安全
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                // 再次获取线程池状态
                int rs = runStateOf(ctl.get());

                // 再次判断
                // 如果满足  rs < SHUTDOWN  说明线程池是RUNNING,状态正常,执行if代码块
                // 如果线程池状态为SHUTDOWN,并且firstTask为null,添加非核心工作处理阻塞队列任务
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 到这,可以添加工作线程。
                    // 校验ThreadFactory构建线程后,不能自己启动线程,如果启动了,抛出异常
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    // private final HashSet workers = new HashSet();
                    // 将new好的Worker添加到HashSet中。
                    workers.add(w);
                     // 获取了HashSet的size,拿到工作线程个数
                    int s = workers.size();
                    // largestPoolSize在记录最大线程个数的记录
                    // 如果当前工作线程个数,大于最大线程个数的记录,就赋值
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 添加工作线程成功
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 如果工作线程添加成功,
            if (workerAdded) {
                // 直接启动Worker中的线程
                t.start();
                // 启动工作线程成功
                workerStarted = true;
            }
        }
    } finally {
        // 做补偿的操作,如果工作线程启动失败,将这个添加失败的工作线程处理掉
        if (! workerStarted)
            addWorkerFailed(w);
    }
    // 返回工作线程是否启动成功
    return workerStarted;
}
/**
* 回滚工作线程的创建。
* - 如果存在,从工作线程集合中移除该工作线程
* - 减少工作线程计数
* - 重新检查是否需要终止,以防该工作线程的存在阻碍了终止
*/
// 工作线程启动失败,需要不的步长操作
private void addWorkerFailed(Worker w) {
    // 因为操作了workers,需要加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 如果w不为null,之前Worker已经new出来了。
        if (w != null)
            // 从HashSet中移除
            workers.remove(w);
        // 同时对ctl进行 - 1,代表去掉了一个工作线程个数
        decrementWorkerCount();
        // 因为工作线程启动失败,判断一下状态的问题,是不是可以走TIDYING状态最终到TERMINATED状态了
        tryTerminate();
    } finally {
        // 释放锁
        mainLock.unlock();
    }
}

ThreadPoolExecutor的Worker工作线程

Worker对象主要包含了两个内容

  • 工作线程要执行任务

  • 工作线程可能会被中断,控制中断

// Worker继承了AQS,目的就是为了控制工作线程的中断。
// Worker实现了Runnable,内部的Thread对象,在执行start时,必然要执行Worker中断额一些操作
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
  
// =======================Worker管理任务================================  
    // 线程工厂构建的线程
    final Thread thread;

    // 当前Worker要执行的任务
    Runnable firstTask;

    // 记录当前工作线程处理了多少个任务。
    volatile long completedTasks;

    // 有参构造
    Worker(Runnable firstTask) {
        // 将State设置为-1,代表当前不允许中断线程
        setState(-1); 
        // 任务赋值
        this.firstTask = firstTask;
        // 基于线程工作构建Thread,并且传入的Runnable是Worker
        this.thread = getThreadFactory().newThread(this);
    }

    // 当thread执行start方法时,调用的是Worker的run方法,
    public void run() {
        // 任务执行时,执行的是runWorker方法
        runWorker(this);
    }


// =======================Worker管理中断================================   
    // 当前方法是中断工作线程时,执行的方法
    void interruptIfStarted() {
        Thread t;
        // 只有Worker中的state >= 0的时候,可以中断工作线程
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                // 如果状态正常,并且线程未中断,这边就中断线程
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
  
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }
    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
    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(); }

  
}

ThreadPoolExecutor的runWorker方法

runWorker就是让工作线程拿到任务去执行即可

并且在内部也处理了在工作线程正常结束和异常结束时的处理方案

// 工作线程启动后执行的任务。
final void runWorker(Worker w) {
    // 拿到当前线程
    Thread wt = Thread.currentThread();
    // 从worker对象中拿到任务
    Runnable task = w.firstTask;
    // 将Worker中的firstTask置位空
    w.firstTask = null;
    // 将Worker中的state置位0,代表当前线程可以中断的
    w.unlock(); // allow interrupts
    // 判断工作线程是否是异常结束,默认就是异常结束
    boolean completedAbruptly = true;
    try {
        // 获取任务
        // 直接拿到第一个任务去执行
        // 如果第一个任务为null,去阻塞队列中获取任务
        while (task != null || (task = getTask()) != null) {
            // 执行了Worker的lock方法,当前在lock时,shutdown操作不能中断当前线程,因为当前线程正在处理任务
            w.lock();
            // 比较ctl >= STOP,如果满足找个状态,说明线程池已经到了STOP状态甚至已经要凉凉了
            // 线程池到STOP状态,并且当前线程还没有中断,确保线程是中断的,进到if内部执行中断方法
            // if(runStateAtLeast(ctl.get(), STOP) && !wt.isInterrupted()) {中断线程}
            // 如果线程池状态不是STOP,确保线程不是中断的。
            // 如果发现线程中断标记位是true了,再次查看线程池状态是大于STOP了,再次中断线程
            // 这里其实就是做了一个事情,如果线程池状态 >= STOP,确保线程中断了。
            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;
                // 当前工作线程处理的任务数+1
                w.completedTasks++;
                // 执行unlock方法,此时shutdown方法才可以中断当前线程
                w.unlock();
            }
        }
        // 如果while循环结束,正常走到这,说明是正常结束
        // 正常结束的话,在getTask中就会做一个额外的处理,将ctl - 1,代表工作线程没一个。
        completedAbruptly = false;
    } finally {
        // 考虑干掉工作线程
        processWorkerExit(w, completedAbruptly);
    }
}
// 工作线程结束前,要执行当前方法
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 如果是异常结束
    if (completedAbruptly) 
        // 将ctl - 1,扣掉一个工作线程
        decrementWorkerCount();

    // 操作Worker,为了线程安全,加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 当前工作线程处理的任务个数累加到线程池处理任务的个数属性中
        completedTaskCount += w.completedTasks;
        // 将工作线程从hashSet中移除
        workers.remove(w);
    } finally {
        // 释放锁
        mainLock.unlock();
    }

    // 只要工作线程凉了,查看是不是线程池状态改变了。
    tryTerminate();

    // 获取ctl
    int c = ctl.get();
    // 判断线程池状态,当前线程池要么是RUNNING,要么是SHUTDOWN
    if (runStateLessThan(c, STOP)) {
        // 如果正常结束工作线程
        if (!completedAbruptly) {
            // 如果核心线程允许超时,min = 0,否则就是核心线程个数
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            // 如果min == 0,可能会出现没有工作线程,并且阻塞队列有任务没有线程处理
            if (min == 0 && ! workQueue.isEmpty())
                // 至少要有一个工作线程处理阻塞队列任务
                min = 1;
            // 如果工作线程个数 大于等于1,不怕没线程处理,正常return
            if (workerCountOf(c) >= min)
                return; 
        }
        // 异常结束,为了避免出现问题,添加一个空任务的非核心线程来填补上刚刚异常结束的工作线程
        addWorker(null, false);
    }
}

ThreadPoolExecutor的getTask方法

工作线程在去阻塞队列获取任务前,要先查看线程池状态

如果状态没问题,去阻塞队列take或者是poll任务

第二个循环时,不但要判断线程池状态,还要判断当前工作线程是否可以被干掉

// 当前方法就在阻塞队列中获取任务
// 前面半部分是判断当前工作线程是否可以返回null,结束。
// 后半部分就是从阻塞队列中拿任务
private Runnable getTask() {
    // timeOut默认值是false。
    boolean timedOut = false; 

    // 死循环
    for (;;) {
        // 拿到ctl
        int c = ctl.get();
        // 拿到线程池的状态
        int rs = runStateOf(c);

        // 如果线程池状态是STOP,没有必要处理阻塞队列任务,直接返回null
        // 如果线程池状态是SHUTDOWN,并且阻塞队列是空的,直接返回null
        if (rs >= SHUTDOWN && 
                (rs >= STOP || workQueue.isEmpty())) {
            // 如果可以返回null,先扣减工作线程个数
            decrementWorkerCount();
            // 返回null,结束runWorker的while循环
            return null;
        }

        // 基于ctl拿到工作线程个数
        int wc = workerCountOf(c);

        // 核心线程允许超时,timed为true
        // 工作线程个数大于核心线程数,timed为true
        boolean timed = allowCoreThreadTimeOut || wc ]]> corePoolSize;

        if (
            // 如果工作线程个数,大于最大线程数。(一般情况不会满足),把他看成false
            // 第二个判断代表,只要工作线程数小于等于核心线程数,必然为false
            // 即便工作线程个数大于核心线程数了,此时第一次循环也不会为true,因为timedOut默认值是false
            // 考虑第二次循环了,因为循环内部必然有修改timeOut的位置
            (wc ]]> maximumPoolSize || (timed && timedOut))
            && 
            // 要么工作线程还有,要么阻塞队列为空,并且满足上述条件后,工作线程才会走到if内部,结束工作线程
            (wc ]]> 1 || workQueue.isEmpty())
           ) {
            // 第二次循环才有可能到这。
            // 正常结束,工作线程 - 1,因为是CAS操作,如果失败了,重新走for循环
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        // 工作线程从阻塞队列拿任务
        try {
            // 如果是核心线程,timed是false,如果是非核心线程,timed就是true
            Runnable r = timed ?
                // 如果是非核心,走poll方法,拿任务,等待一会
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                // 如果是核心,走take方法,死等。
                workQueue.take();
            // 从阻塞队列拿到的任务不为null,这边就正常返回任务,去执行
            if (r != null)
                return r;
            // 说明当前线程没拿到任务,将timeOut设置为true,在上面就可以返回null退出了。
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

ThreadPoolExecutor的关闭方法

首先查看shutdownNow方法,可以从RUNNING状态转变为STOP

// shutDownNow方法,shutdownNow不会处理阻塞队列的任务,将任务全部给你返回了。
public List shutdownNow() {
    // 声明返回结果
    List tasks;
    // 加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 不关注这个方法……
        checkShutdownAccess();
        // 将线程池状态修改为STOP
        advanceRunState(STOP);
        // 无论怎么,直接中断工作线程。
        interruptWorkers();
        // 将阻塞队列的任务全部扔到List集合中。
        tasks = drainQueue();
    } finally {
        // 释放锁
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

// 将线程池状态修改为STOP
private void advanceRunState(int STOP) {
    // 死循环。
    for (;;) {
        // 获取ctl属性的值
        int c = ctl.get();
        // 第一个判断:如果当前线程池状态已经大于等于STOP了,不管了,告辞。
        if (runStateAtLeast(c, STOP) ||
            // 基于CAS,将ctl从c修改为STOP状态,不修改工作线程个数,但是状态变为了STOP
            // 如果修改成功结束
            ctl.compareAndSet(c, ctlOf(STOP, workerCountOf(c))))
            break;
    }
}
// 无论怎么,直接中断工作线程。
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 遍历HashSet,拿到所有的工作线程,直接中断。
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}
// 移除阻塞队列,内容全部扔到List集合中
private List drainQueue() {
    BlockingQueue q = workQueue;
    ArrayList taskList = new ArrayList();
    // 阻塞队列自带的,直接清空阻塞队列,内容扔到List集合
    q.drainTo(taskList);
    // 为了避免任务丢失,重新判断,是否需要编辑阻塞队列,重新扔到List
    if (!q.isEmpty()) {
        for (Runnable r : q.toArray(new Runnable[0])) {
            if (q.remove(r))
                taskList.add(r);
        }
    }
    return taskList;
}

// 查看当前线程池是否可以变为TERMINATED状态
final void tryTerminate() {
    // 死循环。
    for (;;) {
        // 拿到ctl
        int c = ctl.get();
        // 如果是RUNNING,直接告辞。
        // 如果状态已经大于等于TIDYING,马上就要凉凉,直接告辞。
        // 如果状态是SHUTDOWN,但是阻塞队列还有任务,直接告辞。
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        // 如果还有工作线程
        if (workerCountOf(c) != 0) { 
            // 再次中断工作线程
            interruptIdleWorkers(ONLY_ONE);
            // 告辞,等你工作线程全完事,我这再尝试进入到TERMINATED状态
            return;
        }

        // 加锁,为了可以执行Condition的释放操作
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 将线程池状态修改为TIDYING状态,如果成功,继续往下走
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // 这个方法是空的,如果你需要在线程池关闭后做一些额外操作,这里你可以自行实现
                    terminated();
                } finally {
                    // 最终修改为TERMINATED状态
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 线程池提供了一个方法,主线程在提交任务到线程池后,是可以继续做其他操作的。
                    // 咱们也可以让主线程提交任务后,等待线程池处理完毕,再做后续操作
                    // 这里线程池凉凉后,要唤醒哪些调用了awaitTermination方法的线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

再次shutdown方法,可以从RUNNING状态转变为SHUTDOWN

shutdown状态下,不会中断正在干活的线程,而且会处理阻塞队列中的任务

public void shutdown() {
    // 加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 不看。
        checkShutdownAccess();
        // 里面是一个死循环,将线程池状态修改为SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 中断空闲线程
        interruptIdleWorkers();
        // 这个是为了ScheduleThreadPoolExecutor准备的,不管
        onShutdown(); 
    } finally {
        mainLock.unlock();
    }
    // 尝试结束线程
    tryTerminate();
}

// 中断空闲线程
private void interruptIdleWorkers(boolean onlyOne) {
    // 加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            // 如果线程没有中断,那么就去获取Worker的锁,基于tryLock可知,不会中断正在干活的线程
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    // 会中断空闲线程
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

你可能感兴趣的:(技术基础,java,开发语言,并发编程)