ThreadPoolExecutor的源码解析

ThreadPoolExecutor的源码解析

这篇自己肝了很久的一篇文章,里面主要介绍关于对ThreadPoolExecutor源码的绝对详细教程

在你看到此篇,我希望大家最好跟着将源码的注释自己敲一遍,绝对事半功倍!!
祝大家收获满满,哈哈!

本文总纲

在这里插入图片描述

线程池的核心属性

ctl:当前的ctl就是一个int类型的数值,内部是基于AtomicInteger套了一层,进行运算时,是原子性

ctl表示的线程池的两种核心状态:

  1. 线程池的状态: ctl高3位标识线程池的状态
  2. 工作线程的状态:ctl低29位,表示工作线程的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 

COUNT_BITS: 声明了一个常量, COUNT_BITS = 29
Integer.SIZE:在获取Integerbit个数

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

CAPACITY:就是当前工作线程能记录工作线程的最大个数

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

线程池五种状态的表示

1.RUNNING:

只有此状态表示线程池没有问题**,可以正常接受任务处理**

111**:高三位(代表running状态),running表示可以处理任务,或者阻塞队列的任务

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

2.SHUTDOWN:

000:代表shutdown的状态,不会接受新任务,正在处理的任务正常进行,阻塞队列的任务也会完成

private static final int SHUTDOWN   =  0 << COUNT_BITS;

3.STOP:

001:代表我们的stop状态,不会接受新任务,正在处理任务的线程会被中断,阻塞队列的任务一个不管

private static final int STOP   =  1 << COUNT_BITS;

4.TIDYING:

010:代表TIDYING状态,这个状态是shutdown或者stop的状态转换过来的,代表当前线程马上关闭,就是一个过渡状态

private static final int TIDYING    =  2 << COUNT_BITS;

5.TERMINATED

011:代表TERMINATED状态,这个状态是TIDYING状态转换过来的转换过来只需要执行一个terminated方法

private static final int TERMINATED =  3 << COUNT_BITS;

线程池的核心属性整体源码解析代码

//当前的ctl就是一个int类型的数值,内部是基于AtomicInteger套了一层,进行运算时,是原子性的
//ctl表示的线程池的两种核心状态:
//线程池的状态: ctl的高3位标识线程池的状态
//工作线程的状态:ctl的低29位,表示工作线程的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
//声明了一个常量, COUNT_BITS = 29
//Integer.SIZE:在获取Integer的bit的个数
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;

// Packing and unpacking ctl:在使用下面的三个值时,需要传进来ctl
//拿到高三位的值
//基于&运算的特点,保证只会拿到ctl的高三位值
private static int runStateOf(int c)     { return c & ~CAPACITY; }
//基于&运算的特点,保证只会拿到ctl的低29位的值
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

线程池的状态转换图

在这里插入图片描述

ThreadPoolExecutor的有参构造

//无论调用哪个有参构造,都会执行当前的有参构造
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> 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():是提交任务到线程池的核心方法
参数:command就是提交过来的任务

public void execute(Runnable command) {

提交的任务不能为null,否则抛空指针异常

if (command == null)   throw new NullPointerException();

ctl.get():获取核心属性ctl,用于后面的判断

int c = ctl.get();

解释: 如果工作线程个数小于核心线程数,满足要求,添加核心工作线程

workerCountOf(c):查询工作线程个数

corePoolSize:核心线程数

addworker(任务,是核心线程吗): 是否添加工作线程

 if (workerCountOf(c) < corePoolSize) {
     //addworker(任务,是核心线程吗)
     //addworker返回true,代表添加工作线程成功
     //addworker返回false,代表添加工作线程失败
     //addWorker会给予线程池状态以及工作线程个数做判断,查看能否添加工作线程 
     if (addWorker(command, true))
         //工作线程构建出来了,任务也交给command去处理了
         return;
     //说明线程池状态或者是工作线程个数发生了变化,导致添加失败,重新获取一次ctl
     c = ctl.get();
 }

添加核心线程失败,走下面的步骤(上述的步骤都失败,走下面的)

isRunning(c):判断线程池状态是否是running

workQueue.offer(command):基于阻塞队列的offer方法,将任务添加到阻塞队列

在此阻塞队列添加收否成成功又有两种情况:

  • 成功添加
    1. 重新获取ctl
    2. 判断线程池的状态是否为running:
      • 否:任务从阻塞队列移除,并直接执行拒绝策略
      • 是: 继续下一步
    3. 查看工作线程数是否是0个
      • 是:添加一个非核心线程处理
      • 否: 结束本次流程
//添加核心线程失败,走下面的步骤
//判断线程池状态是否是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.即便有核心线程,也可以设置核心线程允许超时,设置allowsCoreThreadTimeOut等于true,表示核心线程可以超时
    else if (workerCountOf(recheck) == 0)
        //为了避免阻塞队列的任务饥饿,添加一个非核心线程处理
        addWorker(null, false);
}

上述条件都不符合,直接直接执行决绝策略,结束

//任务添加到阻塞队列失败
    	//构建一个非核心工作线程
    	//如果添加非核心线程成功,直接结束
        else if (!addWorker(command, false))
            //添加 失败,执行拒绝策略
            reject(command);

完整源码解析

//提交任务到线程池的核心方法
//command就是提交过来的任务
public void execute(Runnable command) {
    //提交的任务不能为null
        if (command == null)
            throw new NullPointerException();
   		//获取核心属性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.即便有核心线程,也可以设置核心线程允许超时,设置allowsCoreThreadTimeOut等于true,表示核心线程可以超时
            else if (workerCountOf(recheck) == 0)
                //为了避免阻塞队列的任务饥饿,添加一个非核心线程处理
                addWorker(null, false);
        }
    	//任务添加到阻塞队列失败
    	//构建一个非核心工作线程
    	//如果添加非核心线程成功,直接结束
        else if (!addWorker(command, false))
            //添加 失败,执行拒绝策略
            reject(command);
    }

ThreadPoolExecutor的execute方法解析完整流程图

在这里插入图片描述
注意,到这里并没有完结撒花哈!~
正在更新中,但是上面的execute()执行流程图我强烈推荐大家跟着画一遍,很有收获的!!!
后面更新对addworker()方法源码的剖析

4.ThreadPoolExecutoraddworker()方法

addWorker()主要分成两大块去看:

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

源码解析

retry: 是给我们的外层for循环添加一个标记,为了方便内层for循环跳出外层for循环使用的

runStateOf(c):拿到ctl高三位的值

int rs = runStateOf(c);

线程池状态判断:
如果线程池状态为SHUTDOWN,并且阻塞队列有任务,工作线程个数为0,添加一个工作线程去处理阻塞队列任务
判断线程池的状态是否大于等于SHUTDOWN,若满足,说明线程池非running状态

if (rs >= SHUTDOWN &&
    //这三个条件都满足,代表要添加非核心工作线程去处理阻塞队列任务
    //有一个没有满足,代表不需要添加,直接返回false
    ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
    //代表不要添加工作线程
    return false;

workerCountOf(c):基于ctl拿到低29位的值,代表当前工作线程个数

int wc = workerCountOf(c);

wc >= CAPACITY:工作线程个数大于最大值,则不能再添加

wc >= (core ? corePoolSize : maximumPoolSize):基于core来判断是否核心,

  1. :基于corePoolSize判断
  2. : 基于maximumPoolSize判断
if (wc >= CAPACITY ||
        wc >= (core ? corePoolSize : maximumPoolSize))
        //代表不能添加,工作线程不满足要求
        return false;

compareAndIncrementWorkerCount(c):针对ctl进行+1,采用CAS方式

    //针对ctl进行+1,采用CAS方式,
    if (compareAndIncrementWorkerCount(c))
        //CAS成功后,直接退出外层循环,代表可以直接执行添加工作线程操作
        break retry;
   

重新获取一次ctl的值

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

runStateOf(c):判断重新获取到的ctl中,表示的线程池状态跟之前的是否有区别

   //若状态不一样,说明有变化,重新去判断线程池的状态
    if (runStateOf(c) != rs)
        //跳出一次外层for循环
        continue retry;

添加工作线程之校验完整源码

 private boolean addWorker(Runnable firstTask, boolean core) {
     //外层for循环校验线程池的状态,内层for循环校验工作线程的个数
     //retry是给我们的外层for循环添加一个标记,为了方便内层for循环跳出外层for循环使用的
     retry:
     for (;;) {
         
         //获取ctl
         int c = ctl.get();
         //拿到ctl高三位的值
         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();  // Re-read ctl
             //判断重新获取到的ctl中,表示的线程池状态跟之前的是否有区别
             //若状态不一样,说明有变化,重新去判断线程池的状态
             if (runStateOf(c) != rs)
                 //跳出一次外层for循环
                 continue retry;
         }
     }
     //=====省略添加工作线程和启动工作线程过程(看下面)
 }

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

声明三个标识:

  1. workerStarted: 表示工作线程启动没(默认false)
  2. workerAdded:工作线程添加没(默认false)
  3. Worker: 代表工作线程(默认为null)
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;

构建工作线程,并且将任务传递进去

 w = new Worker(firstTask);

获取Worker中的Thread对象

final Thread t = w.thread;

判断Thread对象是否不为null,在new Worker时,内部会通过给予的ThreadFactory去构建Thread交给Worker

 if (t != null) 

加锁,保证使用workers成员变量以及对largestPoolSize赋值时,保证线程安全

 	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();

rs:再次获取线程池状态

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

rs < SHUTDOWN:若满足rs < SHUTDOWN,说明线程池时RUNNING状态,状态正常,执行if代码块

(rs == SHUTDOWN && firstTask == null):若线程池状态为SHUTDOWN,并且firstTask为null,添加非核心工作线程处理阻塞队列任务

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

t.isAlive():检验ThreadFactory构建线程后,不能自己启动线程,如果启动了,抛出异常

if (t.isAlive())   
    throw new IllegalThreadStateException();	

将new好的worker添加到HashSet

当中的workers:就是HashSet集合

   //private final HashSet<Worker> workers = new HashSet<Worker>();
    workers.add(w);

获取HashSetsize,拿到工作线程个数

int s = workers.size();

largestPoolSize:在记录最大线程个数的记录
s > largestPoolSize:如果当前工作线程个数,大于最大线程个数的记录,就赋值

if (s > largestPoolSize)
    largestPoolSize = s;

添加工作线程成功

workerAdded = true;

addWorkerFailed(): 工作线程启动失败,需要做的补偿操作

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();
    }
}

第二块完整源码

private boolean addWorker(Runnable firstTask, boolean core) {
    //========省略校验线程池的状态以及工作线程的个数代码(看上面的)
	
    //添加工作线程并且启动工作线程
    //声明了三个标识:
    //workerStarted: 工作线程启动没(默认false)
    boolean workerStarted = false;
    //workerAdded:工作线程添加没(默认false)
    boolean workerAdded = false;
    //Worker: 代表工作线程(默认为null)
    Worker w = null;
    try {
        //构建工作线程,并且将任务传递进去
        w = new Worker(firstTask);
        //获取Worker中的Thread对象
        final Thread t = w.thread;
        //判断Thread对象是否不为null,在new Worker时,内部会通过给予的ThreadFactory去构建Thread交给Worker
        //若t=null,代表ThreadFactory有问题
        if (t != null) {
            //加锁,保证使用workers成员变量以及对largestPoolSize赋值时,保证线程安全
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 再次获取线程池状态
                int rs = runStateOf(ctl.get());
				//再次判断
                //若满足rs < SHUTDOWN,说明线程池时RUNNING状态,状态正常,执行if代码块
                if (rs < SHUTDOWN ||
                    //若线程池状态为SHUTDOWN,并且firstTask为null,添加非核心工作线程处理阻塞队列任务
                    (rs == SHUTDOWN && firstTask == null)) {
                    //到这,可以添加工作线程
                    if (t.isAlive()) // t.isAlive():检验ThreadFactory构建线程后,不能自己启动线程,如果启动了,抛出异常
                        throw new IllegalThreadStateException();	
                    //private final HashSet<Worker> workers = new HashSet<Worker>();
                    //将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();
    }
}

5.ThreadPoolExecutorworker()方法

worker对象

主要包含了两个内容

  • 工作线程要执行任务
  • 工作线程可能会被中断,控制中断

Worker管理任务

thread:线程工厂构建的线程

final Thread thread;

firstTask:当前worker要执行的任务

Runnable firstTask;

completedTasks:记录当前工作线程处理了多少个任务

volatile long completedTasks;

Worker的有参构造

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

run():调用 runWorker进行任务的执行

public void run() {
    //任务执行时,执行的是runWorker方法
    runWorker(this);
}

Worker管理中断

这块其实没有什么好说的,主要我们需要看里面的一个方法,是关键

interruptIfStarted():是在中断工作线程时,执行的方法

//当前方法是在中断工作线程时,执行的方法
void interruptIfStarted() {
    Thread t;
    //只有Worker中state>=0时,可以中断工作线程
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            //如果状态正常,并且线程未中断,这边就中断线程
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}

worker()完整源码解析附注释

//worker继承了AQS,目的就是为控制工作线程的中断
//worker实现了Runnable,内部的Thread对象,在执行start时,必然会执行worker中断的一些操作
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {

    private static final long serialVersionUID = 6138294804551838833L;
    //==============Worker管理任务==========
	//线程工厂构建的线程
    final Thread thread;
    //当前worker要执行的任务
    Runnable firstTask;
    //记录当前工作线程处理了多少个任务
    volatile long completedTasks;

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

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

    //==============Worker管理中断==========
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

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

6.ThreadPoolExecutorrunWorker()方法

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

源码剖析:

wt:拿到当前线程

Thread wt = Thread.currentThread();

task:从Worker对象中拿到任务

Runnable task = w.firstTask;

Worker中的firstTask置为空

w.firstTask = null;

将Worker中的state置为0,代表当前线程可以中断

w.unlock();

completedAbruptly: 判断工作线程是否是异常结束,默认就是异常结束

boolean completedAbruptly = true;

获取任务:

1.task != null:直接拿到第一个任务区执行
2.task = getTask()) != null如若第一个任务为null,去阻塞队列中那任务

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

执行Worker的Lock方法,当前在Lock时,shutdown操作不能中断当前线程,因为当前线程正在处理任务

w.lock();

1.(runStateAtLeast(ctl.get(), STOP) && !wt.isInterrupted() :线程池到STOP状态,并且当前线程还没有中断,确保线程是中断的,进到if内部执行中断方法

2.(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))&& !wt.isInterrupted():如果线程池状态非STOP状态,确保线程不是中断的,若发现中断标记位为true了,再次查看线程池状态是大于STOP了–>再次中断线程

if ((runStateAtLeast(ctl.get(), STOP) ||(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) 
                && !wt.isInterrupted())

钩子函数:在线程池中没有做任何的操作,若需要再线程池任务执行前后做一些任务处理,需要自己重写实现钩子函数
beforeExecute():前置钩子函数(点进源码会发现啥都没有,需要自己实现)

beforeExecute(wt, task);

执行任务

task.run();          

后置钩子函数

afterExecute(task, thrown);                        

完整源码解析

//工作线程启动后执行的任务
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 {
        //获取任务:
        //1.直接拿到第一个任务区执行
        //2.如若第一个任务为null,去阻塞队列中那任务
        while (task != null || (task = getTask()) != null) {
            //执行Worker的Lock方法,当前在Lock时,shutdown操作不能中断当前线程,因为当前线程正在处理任务
            w.lock();
            // 比较ctl>=STOP ,如果满足这个状态,说明线程池已经到了STOP状态,甚至已经要结束,
            //也就是:若线程池状态>=STOP,确保线程中断 
            //1.(runStateAtLeast(ctl.get(), STOP) && !wt.isInterrupted() 线程池到STOP状态,并且当前线程还没有中断,确保线程是中断的,进到if内部执行中断方法
            //2.如果线程池状态非STOP状态,确保线程不是中断的,若发现中断标记位为true了,再次查看线程池状态是大于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);
    }
}

介绍processWorkerExit()

工作线程结束前,要执行的此方法

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

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; // replacement not needed
        }
        //异常结束,为避免出问题,添加一个空任务的非核心线程来填补上刚刚结束的工作线程
        addWorker(null, false);
    }
}

7.ThreadPoolExecutorgetTask()

说明:工作线程在去获取阻塞队列任务前,首先要查看线程池的状态,若状态没有问题,进行阻塞队列的take或者poll任务;对于第二个循环,不仅要判断线程池的状态,还要判断当前工作线程是否可以被干掉

当前方法就是在阻塞队列中获取任务

  • 前半部分是判断当前工作线程是否是可以返回null结束
  • 后半部分就是从阻塞队列中拿任务的

源码解析

timeout:默认值是false

boolean timedOut = false; 

死循环

for (;;) 
第一次循环

拿到ctl

int c = ctl.get();

拿到线程池的状态

int rs = runStateOf(c);

rs >= SHUTDOWN:若线程池状态是STOP,不需在处理阻塞队列的任务,直接返回null
rs >= STOP || workQueue.isEmpty()):若线程池状态是SHUTDOWN,并且阻塞队列是空,直接返回null

if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
    //若可以返回null,先扣减工作线程个数
    decrementWorkerCount();
    //返回null,结束runWorker的while循环
    return null;
}

wc:基于ctl拿到工作线程个数

 int wc = workerCountOf(c);
第二次循环

wc > maximumPoolSize:若工作线程个数大于最大线程数(一般情况不会满足,即通常为false)

timed && timedOut :

  • 代表工作线程**<=**核心线程数,必为false;
  • 即便工作线程个数>核心线程个数,此时第一次循环也不会为true,因为timeOut默认值是false
  • 为什么会有? 考虑第二次循环,因循环内部必有修改timeOut的位置

wc > 1 || workQueue.isEmpty()):要么工作线程还有,要么阻塞队列为空并且满足上述条件后,工作线程才会走到if内部,结束工作线程

if ((wc > maximumPoolSize || (timed && timedOut))
    //要么工作线程还有,要么阻塞队列为空并且满足上述条件后,工作线程才会走到if内部,结束工作线程
    && (wc > 1 || workQueue.isEmpty())) {
    //第二次循环才有可能到这
    //正常结束:工作线程减一,因为是CAS操作,若失败,重新走for循环
    if (compareAndDecrementWorkerCount(c))
        return null;
    continue;
}
工作线程从阻塞队列拿任务

若是核心线程,timed为false,若是非核心线程,timed就是true

  • 若是非核心,走poll方法,拿任务等待一会
  • 若是核心走take,死等
Runnable r = timed ?
//若是非核心,走poll方法,拿任务等待一会
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
//若是核心走take,死等
workQueue.take();

完整源码剖析

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
        //or 工作线程个数大于核心线程个数 timed为true
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		//========第二次循环=======================
        if (//wc > maximumPoolSize:若工作线程个数大于最大线程数(一般情况不会满足,即通常为false)
            //timed && timedOut :代表工作线程<=核心线程数,必为false; 即便工作线程个数>核心线程个数,此时第一次循环也不会为true,因为timeOut默认值是false
            //考虑第二次循环,因循环内部必有修改timeOut的位置
            (wc > maximumPoolSize || (timed && timedOut))
            //要么工作线程还有,要么阻塞队列为空并且满足上述条件后,工作线程才会走到if内部,结束工作线程
            && (wc > 1 || workQueue.isEmpty())) {
            //第二次循环才有可能到这
            //正常结束:工作线程减一,因为是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;
        }
    }
}

8.ThreadPoolExecutor的关闭方法

ShutdownNow()

首先我们需要查看ShutdownNow()方法,可以让线程池状态从RUNNING直接转为STOP状态

完整源码,重点看里面的方法

//shutdownNow方法不会阻塞队列的任务,将任务全部返回
public List<Runnable> shutdownNow() {
    //声明返回结果
    List<Runnable> tasks;
    //加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        //关于系统访问决策的,在此次不关注,不作解释
        checkShutdownAccess();
        //将线程池状态改为STOP
        advanceRunState(STOP);
        //无论怎样,直接中断工作线程
        interruptWorkers();
        //将阻塞队列的任务全部扔到list集合中
        tasks = drainQueue();
    } finally {
        //释放锁
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

advanceRunState():

将线程池状态改为STOP

private void advanceRunState(int STOP) {
    //死循环
    for (;;) {
        
       //获取ctl
        int c = ctl.get();
        //runStateAtLeast(c, STOP):当前线程池状态>=STOP,不管了
        //ctl.compareAndSet(c, ctlOf(STOP, workerCountOf(c))): 
        //    基于CAS,将ctl从c修改为STOP状态,不修改工作线程个数,但是状态改为了STOP
        //    若修改成功,结束
        if (runStateAtLeast(c, STOP) ||
            ctl.compareAndSet(c, ctlOf(STOP, workerCountOf(c))))
            break;
    }
}

interruptWorkers:

直接中断工作线程

private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        //遍历HASHset,拿到所有的工作线程,直接中断
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}

drainQueue:

将阻塞队列的任务全部移除扔到list集合中

private List<Runnable> drainQueue() {
    BlockingQueue<Runnable> q = workQueue;
    ArrayList<Runnable> taskList = new ArrayList<Runnable>();
    //阻塞队列自带,直接清空阻塞队列内容扔到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;
}

tryTerminate:

查看当前线程池是否可以变为TERMINATED状态

final void tryTerminate() {
    //死循环
    for (;;) {
        //拿到ctl
        int c = ctl.get();
        //若是RUNNING,直接return
        //若状态>=TIDYING,要结束了,直接return
        //若状态=SHUTDOWN,但阻塞队列还是任务,直接return
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        //若还有工作线程,
        if (workerCountOf(c) != 0) { // Eligible to terminate
            //再次中断工作线程
            interruptIdleWorkers(ONLY_ONE);
            //return,就是等工作线程全结束,再次尝试就如到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()方法

再次我们需要查看Shutdown()方法,可以从RUNNING直接转为SHUTDOWN状态

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

public void shutdown() {
    //加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        //系统的调用策略,不看
        checkShutdownAccess();
        //一个死循环方法,将线程池状态修改为shutdown状态
        advanceRunState(SHUTDOWN);
        //中断空闲线程
        interruptIdleWorkers();
        //为了ScheduledThreadPoolExecutor的线程作准备的,不管
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    //尝试结束线程
    tryTerminate();
}

interruptIdleWorkers:中断空闲线程

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();
    }
}

好了,此篇总结下吧

后面我会持续进行更新此篇,直到整个ThreadPoolExecutor源码分析完为止(不拆成几篇博客了**,方便以后**学习查看)

哈哈哈,已经都完成了哦,很详细了,我肝了两三个晚上的结果,希望对你有帮助

感觉不错,点个赞呗,祝你好运加倍!~

道阻且长,行则将至!诸君共勉之
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值