线程池:ThreadPoolExecutor 源码解析

1、继承关系图

 

2、简介

 

大体过程:

1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。 
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务 
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程 
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

线程池的优势:

  1. 降低创建线程和销毁线程的性能开销
  2. 提高响应速度,当有新任务需要执行是不需要等待线程创建就可以立马执行
  3. 合理的设置线程池大小可以避免因为线程数超过硬件资源瓶颈带来的问题

 

3、成员变量

public class ThreadPoolExecutor extends AbstractExecutorService {
    ......
}

(1)线程池状态 成员变量及获取方法

//记录线程池状态和线程数量(总共32位,前三位表示线程池状态,后29位表示线程数量)
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//线程数量统计位数29  Integer.SIZE=32 
private static final int COUNT_BITS = Integer.SIZE - 3;
//容量 000 11111111111111111111111111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

存储在高3位的运行状态,低位都一样
//运行中 111 00000000000000000000000000000
private static final int RUNNING    = -1 << COUNT_BITS;
//关闭 000 00000000000000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//停止 001 00000000000000000000000000000
private static final int STOP       =  1 << COUNT_BITS;
//整理 010 00000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;
//终止 011 00000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

//获取运行状态(获取前3位)
private static int runStateOf(int c)     { return c & ~CAPACITY; }
//获取线程个数(获取后29位)
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

 ctl是主要的控制状态,是一个复合类型的变量,其中包括了两个概念。

  • workerCount:表示有效的线程数目

  • runState:线程池里线程的运行状态

RUNNING:接受新任务并且处理阻塞队列里的任务

SHUTDOWN:拒绝新任务但是处理阻塞队列里的任务

STOP:拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务

TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为0,将要调用terminated方法

TERMINATED:终止状态。terminated方法调用完成以后的状态

线程池状态转换:

RUNNING -> SHUTDOWN

显式调用shutdown()方法, 或者隐式调用了finalize()方法

(RUNNING or SHUTDOWN) -> STOP

显式调用shutdownNow()方法

SHUTDOWN -> TIDYING

当线程池和任务队列都为空的时候

STOP -> TIDYING

当线程池为空的时候

TIDYING -> TERMINATED

当 terminated() hook 方法执行完成时候

(2)线程池大小相关成员变量

private volatile int corePoolSize;  // 核心线程数
private volatile int maximumPoolSize;  // 最大线程数
private int largestPoolSize;   //用来记录线程池中曾经出现过的最大线程数

private volatile long keepAliveTime; // 存活时间

// true的时候,core线程在keepAliveTime后将被释放,false时即使线程空闲也不释放;
private volatile boolean allowCoreThreadTimeOut;

maximumPoolSize:是一个静态变量,在变量初始化的时候,有构造函数指定

largestPoolSize: 是一个动态变量,是记录Poll曾经达到的最高值,也就是 largestPoolSize<= maximumPoolSize

(1)corePoolSize:核心线程数,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务

除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。

默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中

allowCoreThreadTimeOut为false时,核心线程会一直存活,哪怕是一直空闲着。而当allowCoreThreadTimeOut为true时核心线程空闲时间超过keepAliveTime时会被回收

(2)maximumPoolSize:线程池最大线程数,它表示在线程池中最多能创建多少个线程

当线程池中的线程达到最大时,此时添加任务将会采用拒绝策略,默认的拒绝策略是抛出一个运行时错误(RejectedExecutionException)。

值得一提的是,当初始化时用的工作队列为LinkedBlockingDeque时,这个值将无效。

(3)keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止

默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。

但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

(3)工作队列、工作线程、锁 相关

private final ReentrantLock mainLock = new ReentrantLock();  //可重入锁
private final Condition termination = mainLock.newCondition();   // 条件队列

// 线程池当中的线程集合,只有当拥有mainLock锁的时候,才可以进行访问
private final HashSet<Worker> workers = new HashSet<Worker>();   
// 任务队列
private final BlockingQueue<Runnable> workQueue;  

// 已完成任务的计数器。仅在工作线程终止时更新。只能在主锁下访问。
private long completedTaskCount;

(1)workQueue

任务队列,常用有三种队列,即SynchronousQueue,LinkedBlockingDeque(无界队列),ArrayBlockingQueue(有界队列)

(4)处理策略、线程工厂

// 表示当拒绝处理任务时的策略
private volatile RejectedExecutionHandler handler;  
// 默认处理策略是: AbortPolicy
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

private volatile ThreadFactory threadFactory;  // 线程工厂

(1)RejectedExecutionHandler

也是一个接口,只有一个方法,当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法。默认是抛出一个运行时异常。

一共四种策略:

AbortPolicy:默认的拒绝策略,当继续有任务到来时直接抛出异常

DiscardPolicy:直接抛弃该任务,不处理

DiscardOldestPolicy:抛弃queue中的第一个任务(旧任务),再次执行该任务(新任务)

CallerRunsPolicy:直接由执行该方法的线程继续执行该任务,除非调用了shutdown方法,这个任务才会被丢弃,否则继续执行该任务会发生阻塞

关于 处理策略,具体见下面 内部类章节

(2)threadFactory

创建线程的工厂

 

4、重要内部类

4.0、RejectedExecutionHandler 接口(这个不是它的内部类)

不是 ThreadPoolExecutor  的内部类,只是 ThreadPoolExecutor  引用了它。但是ThreadPoolExecutor 用到的4种拒绝策略都是 RejectedExecutionHandler 接口 的实现类

 RejectedExecutionHandler 接口 内部只有1个方法:rejectedExecution

当我们创建线程池并且提交任务失败时,线程池会回调RejectedExecutionHandler接口的rejectedExecution(Runnable task, ThreadPoolExecutor executor)方法来处理线程池处理失败的任务,其中task 是用户提交的任务,而executor是当前执行的任务的线程池。

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

下面的4个实现类,都只是仅仅实现了这个方法。

4.1、AbortPolicy 策略类

默认的拒绝策略,当继续有任务到来时直接抛出异常

public static class AbortPolicy implements RejectedExecutionHandler {

    // 构造方法
    public AbortPolicy() { }

    // 直接抛出异常
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                                        " rejected from " +
                                                        e.toString());
    }
}

4.2、DiscardPolicy 策略类

直接抛弃该任务,不处理

public static class DiscardPolicy implements RejectedExecutionHandler {

    public DiscardPolicy() { }
    
    // 直接抛弃任务,什么都不做!!!
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
}

4.3、DiscardOldestPolicy 策略类

抛弃queue中的第一个任务(最旧的任务),再次执行该任务(最新的任务)

public static class DiscardOldestPolicy implements RejectedExecutionHandler {

    public DiscardOldestPolicy() { }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        // 如果线程池没有关闭,就从取出任务队列的头元素,执行这个新任务
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

4.4、CallerRunsPolicy 策略类

 直接由执行该方法的线程继续执行该任务(一般提交任务的线程一般都不是线程池中的线程,也就是让提交任务线程自己执行该任务,前提是 线程池没有关闭)

除非调用了shutdown方法,这个任务才会被丢弃,否则继续执行该任务会发生阻塞

public static class CallerRunsPolicy implements RejectedExecutionHandler {

    public CallerRunsPolicy() { }

    // 直接由执行该任务的线程执行该任务
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

4.5、Worker (!!!)

4.5.1、简介

实现了 Runnable,继承了AQS

主要是控制在线程执行任务时的interrupt操作的。它继承了AbstractQueuedSynchronizer类,实现了一个非重入的锁。该锁会保护一个正在等待任务被执行的Worker不被interrupt操作打断

它就是一个运行task的线程,没有task就去queue里去take,它继承AQS,初始的时候置state为-1 

工作线程,ThreadPoolExecutor中一个线程就是一个Worker对象,它与一个线程绑定,当Worker执行完毕就是线程执行完毕

Worker具有了锁的特性,而且是一把互斥锁。runWorker使用了Worker这把互斥锁,通过它保护用户任务的执行。

除了Worker本身的run方法调用了runWorker之外,没有其他地方执行了调用,而run方法的调用本身就是线程封闭式的,不会存在一个线程闯入进来打乱线程的执行。也就是runWorker的执行不存在竞争,为什么要用锁来保护?(Worker为什么要锁???

目的是中断的控制:Worker代表工作线程,它正在执行任务,这时候想要中断它怎么做?Woker严格意义来说不是线程对象,但是它的内部包含了线程对象,这个线程对象就是运行Worker称之为工作线程的体现。想中断Worker的操作,那么中断它内部的这个线程就行了,于是我们可以这样操作:

Thread t = worker.thread;
t.interrupt();

如果task代码实现里有Thread.sleep或者join等,那就会被中断,task运行没完成。 

当提交一个任务时,如果需要创建一个线程(何时需要在下一节中探讨)时,就调用线程工厂创建一个线程,同时将线程绑定到Worker工作队列中。需要说明的是,Worker队列构造的时候带着一个任务Runnable,因此Worker创建时总是绑定着一个待执行任务。换句话说,创建线程的前提是有必要创建线程(任务数已经超出了线程或者强制创建新的线程,至于为何强制创建新的线程后面章节会具体分析),不会无缘无故创建一堆空闲线程等着任务。这是节省资源的一种方式。

一旦线程池启动线程后(调用线程run())方法,那么线程工作队列Worker就从第1个任务开始执行(这时候发现构造Worker时传递一个任务的好处了),一旦第1个任务执行完毕,就从线程池的任务队列中取出下一个任务进行执行。循环如此,直到线程池被关闭或者任务抛出了一个RuntimeException。

由此可见,线程池的基本原理其实也很简单,无非预先启动一些线程,线程进入死循环状态,每次从任务队列中获取一个任务进行执行,直到线程池被关闭。如果某个线程因为执行某个任务发生异常而终止,那么重新创建一个新的线程而已。如此反复。

其实,线程池原理看起来简单,但是复杂的是各种策略,例如何时该启动一个线程,何时该终止、挂起、唤醒一个线程,任务队列的阻塞与超时,线程池的生命周期以及任务拒绝策略等等。

4.5.2、源码分析

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {

    private static final long serialVersionUID = 6138294804551838833L;

    // 工作线程,如果工厂失败则为空
    final Thread thread;
    // 初始执行的任务
    Runnable firstTask;
    // 当前工作线程已完成的任务计数
    volatile long completedTasks;

    // 构造方法
    Worker(Runnable firstTask) {
        setState(-1); // 禁止中断直到 runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }

    // 重写Runnable的run方法
    public void run() {
        // 调用ThreadPoolExecutor的runWorker方法
        runWorker(this);
    }

    // 代表是否独占锁,0-非独占  1-独占
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    // 重写AQS的tryAcquire方法尝试获取锁
    protected boolean tryAcquire(int unused) {
        // CAS获取锁;如果成功,将占有锁的线程设置为当前线程
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    // 重写AQS的tryRelease尝试释放锁
    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);  //设置AQS同步状态为0
        return true;
    }

    // 下面的代码块,是AQS中的方法
    // 加锁
    public void lock()        { acquire(1); }
    public boolean tryLock()  { return tryAcquire(1); }
    // 解锁
    public void unlock()      { release(1); }
    public boolean isLocked() { return isHeldExclusively(); }

    // start之后,中断线程
    void interruptIfStarted() {
        Thread t;
        // 如果已经加锁,并且没有被中断,就中断线程
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}

 

5、构造方法

就是初始化一些参数信息,没有的话就默认

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                                        Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                                                Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                                                            threadFactory, defaultHandler);
}
//上面的3个构造方法都是调用的本方法
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    // 参数异常
    if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
        throw new IllegalArgumentException();
    // 控制针异常
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();

    this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();

    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

 

6、核心方法

execute(Runnable command)

public void execute(Runnable command) {
    //需要执行的任务command为空,抛出空指针异常
    if (command == null)  // 1
        throw new NullPointerException();

          /*
          *执行的流程实际上分为三步
          *1、如果运行的线程小于corePoolSize,以用户给定的Runable对象新开一个线程去执行
          *  并且执行addWorker方法会以原子性操作去检查runState和workerCount,以防止当返回false的
          *  时候添加了不应该添加的线程
          *2、 如果任务能够成功添加到队列当中,我们仍需要对添加的线程进行双重检查,有可能添加的线程在前
          *  一次检查时已经死亡,又或者在进入该方法的时候线程池关闭了。所以我们需要复查状态,并有有必
          *  要的话需要在停止时回滚入列操作,或者在没有线程的时候新开一个线程
          *3、如果任务无法入列,那我们需要尝试新增一个线程,如果新建线程失败了,我们就知道线程可能关闭了
          *  或者饱和了,就需要拒绝这个任务
          */

    //获取线程池的控制状态
    int c = ctl.get();  // 2

    //通过workCountOf方法算workerCount(线程个数)值,小于corePoolSize
    if (workerCountOf(c) < corePoolSize) {
        //添加任务到worker集合当中(包含task-->Worker,worker.run()等操作)
        if (addWorker(command, true)) 
            return;  //成功返回
        //失败的话再次获取线程池的控制状态
        c = ctl.get();
    }

    /*
    *判断线程池是否正处于RUNNING状态
    *是的话添加Runnable对象到workQueue队列当中
    */
    if (isRunning(c) && workQueue.offer(command)) {  // 3

        //再次获取线程池的状态
        int recheck = ctl.get();

        //再次检查状态(有可能添加的线程在前一次检查时已经死亡,又或者在进入该方法的时候线程池关闭了。)
        //线程池不处于RUNNING状态,将任务从workQueue队列中移除
        if (! isRunning(recheck) && remove(command))
            //拒绝任务
            reject(command);
        //workerCount(线程数)等于0
        else if (workerCountOf(recheck) == 0)  // 4
            //添加worker
            addWorker(null, false);
    }
    //加入阻塞队列失败(线程可能关闭了或者饱和了,就需要拒绝这个任务)
    //则尝试以线程池最大线程数新开线程去执行该任务
    else if (!addWorker(command, false))  // 5 
        //执行失败则拒绝任务
        reject(command);
}

我们来说一下上面这个代码的流程:

1、首先判断任务是否为空,空则抛出空指针异常
2、不为空则获取线程池控制状态,判断小于corePoolSize,添加到worker集合当中执行,

  • 如成功,则返回
  • 失败的话再接着获取线程池控制状态,因为只有状态变了才会失败,所以重新获取
    3、判断线程池是否处于运行状态,是的话则添加command到阻塞队列,加入时也会再次获取状态并且检测
    ​ 状态是否不处于运行状态,不处于的话则将command从阻塞队列移除,并且拒绝任务
    4、如果线程池里没有了线程,则创建新的线程去执行获取阻塞队列的任务执行
    5、如果以上都没执行成功,则需要开启最大线程池里的线程来执行任务,失败的话就丢弃

execute执行流程.jpg


addWorker(Runnable firstTask, boolean core) 

// core==true,则用corePoolSize
// core==false,则用maximumPoolSize
private boolean addWorker(Runnable firstTask, boolean core) {
    //外部循环标记
    retry:
    //外层死循环
    for (;;) {
        //获取线程池控制状态
        int c = ctl.get();   //ctl是AtomicInteger 
        //获取线程池运行状态
        int rs = runStateOf(c);
      ​
        // Check if queue empty only if necessary.

        /**
         *1、如果线程池runState至少已经是shutdown
         *2、下面情况中出现1个,则addWorker失败
         *      - runState!=shutdown,即状态已经大于shutdown了
         *      - firstTask不为空,代表线程池已经关闭了(结合上面的shutdown)还在传任务进来
         *      - 队列为空:既然任务已经为空,队列为空,就不需要往线程池添加任务了
         */
        if (rs >= SHUTDOWN &&  //runState大于等于SHUTDOWN,初始位RUNNING
                    ! (rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
      ​
        //内层死循环
        for (;;) {

            //获取线程池的workerCount(工作线程)数量
            int wc = workerCountOf(c);
            //如果workerCount超出最大值或者大于corePoolSize/maximumPoolSize,返回false
            if (wc >= CAPACITY ||
                      wc >= (core ? corePoolSize : maximumPoolSize))
                return false;

            //通过CAS操作,使workerCount数量+1,成功则跳出循环,回到retry标记(外层循环)
            if (compareAndIncrementWorkerCount(c))
                break retry;

            //CAS操作失败,再次获取线程池的控制状态
            c = ctl.get();  
            //如果当前runState不等于刚开始获取的runState,则跳出内层循环,继续外层循环
            if (runStateOf(c) != rs)
                continue retry;
            //CAS由于更改workerCount而失败,继续内层循环
        } //内层循环结束
    }  //外层循环结束
      ​
//通过以上循环,能执行到这是workerCount成功+1了(!!!)

    boolean workerStarted = false;   //worker开始标记
    boolean workerAdded = false;     //worker添加标记
    Worker w = null;    //初始化worker为null
    try {
        //初始化一个当前Runnable对象的worker对象(封装task --> worker)
        w = new Worker(firstTask);
        
        final Thread t = w.thread;    //获取该worker对应的线程
        //如果线程不为null
        if (t != null) {
            //初始线程池的锁
            final ReentrantLock mainLock = this.mainLock;
            
            mainLock.lock();    //获取锁
            try {
                //获取锁后再次检查,获取线程池runState
                int rs = runStateOf(ctl.get());
                //当runState小于SHUTDOWN 或者 runState等于SHUTDOWN并且firstTask为null
                if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                          
                    if (t.isAlive())   //线程已存活
                        //线程未启动就存活,抛出IllegalThreadStateException异常
                        throw new IllegalThreadStateException();

                    workers.add(w);    //将worker对象添加到workers(HashSet<Worker>)当中
                    int s = workers.size();    //获取workers集合的大小
                    //更新largestPoolSize(largestPoolSize是线程池出现过的最大线程数)
                    if (s > largestPoolSize)  
                        largestPoolSize = s;
                    //标记worker已经被添加
                    workerAdded = true;
                }
            } finally {
                //释放锁
                mainLock.unlock();
            }

            //如果worker添加成功
            if (workerAdded) {
                t.start();    //启动线程
                workerStarted = true;   //标记worker已经启动
            }
        }
    } finally {
        //如果worker没有启动成功
        if (! workerStarted)
            addWorkerFailed(w);    //workerCount-1的操作
    }
    return workerStarted;    //返回worker是否启动的标记
}

简单说一下这个代码的流程:

1、获取线程池的控制状态,进行判断,不符合则返回false,符合则下一步
2、死循环,判断workerCount是否大于上限,或者大于corePoolSize/maximumPoolSize,没有的话则对workerCount+1操作,
3、如果不符合上述判断或+1操作失败,再次获取线程池的控制状态,获取runState与刚开始获取的runState相比,不一致则跳出内层循环继续外层循环,否则继续内层循环
4、+1操作成功后,使用重入锁ReentrantLock来保证往workers当中添加worker实例,添加成功就启动该实例。

addWorker.jpg


addWorkerFailed(Worker w) 

addWorker方法添加worker失败,并且没有成功启动任务的时候,就会调用此方法,将任务从workers中移除,并且workerCount做-1操作。

private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();    //获取锁
    try {
        //如果worker不为null
        if (w != null)
            workers.remove(w);   //workers移除worker
            decrementWorkerCount();   //通过CAS操作,workerCount-1
            tryTerminate();
    } finally {
        mainLock.unlock();    //释放锁
    }
}

tryTerminate() 

当对线程池执行了非正常成功逻辑的操作时,都会需要执行tryTerminate尝试终止线程池

final void tryTerminate() {
    //死循环
    for (;;) {
        int c = ctl.get();    //获取线程池控制状态

        /*
         *出现以下情况的任何1种,都直接return,不能进行终止操作
         *    (1)线程池处于RUNNING状态
         *    (2)线程池状态最小大于TIDYING(也就是 TIDYING或者TERMINATED)
         *        TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为0,将要调用terminated方法
         *        TERMINATED:终止状态。terminated方法调用完成以后的状态
         *    (3)线程池==SHUTDOWN并且workQUeue不为空
         */
        if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;

        //如果workerCount(工作线程)不为0,有资格终结
        if (workerCountOf(c) != 0) { 
            interruptIdleWorkers(ONLY_ONE);   //ONLY_ONE = true
            return;
        }
      ​
        //获取线程池的锁(Worker自带的)
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();  //获取锁
        try {
            //通过CAS操作,设置线程池状态为TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();  // protected void terminated() { },留给子类实现
                } finally {
                    //设置线程池的状态为TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    //发送释放信号给在termination条件上等待的线程
                    // private final Condition termination = mainLock.newCondition();
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();    //释放锁
        }
        // else retry on failed CAS   
    }
}

runWorker(Worker w) 

该方法的作用就是去执行任务

仅仅被 Worker.run() 调用

final void runWorker(Worker w) {
    
    Thread wt = Thread.currentThread();   //获取当前线程
    Runnable task = w.firstTask;    //获取worker里的任务
    w.firstTask = null;   //将worker实例的任务赋值为null

    /*
     *unlock方法会调用AQS的release方法
     *    release方法会调用具体实现类也就是Worker的tryRelease方法(也就是将AQS状态置为0,允许中断)
     */
    w.unlock();   //允许中断
    boolean completedAbruptly = true;   //是否突然完成
    try {
        //worker实例的task不为空,或者通过getTask获取的不为空
        while (task != null || (task = getTask()) != null) {

            w.lock();  //获取锁

            /*
             *获取线程池的控制状态,至少要大于STOP状态
             *    如果状态不对,检查当前线程是否中断并清除中断状态,并且再次检查线程池状态是否大于STOP
             *    如果上述满足,检查该对象是否处于中断状态,不清除中断标记
             */
            if ((runStateAtLeast(ctl.get(), STOP) || 
                                (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) 
                    && !wt.isInterrupted())
                //中断改对象
                wt.interrupt();
            try {
                // protected void beforeExecute(Thread t, Runnable r) { }
                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 {
                    // protected void afterExecute(Runnable r, Throwable t) { }
                    afterExecute(task, thrown);    //执行完后调用的方法,也是由子类具体实现
                }
            } finally {  //task执行完后
                task = null;   //task设置为null
                w.completedTasks++;   //已完成任务数+1(Worker w)
                w.unlock();   //释放锁
            }
        }
        completedAbruptly = false;
    } finally {
        //处理并退出当前worker
        processWorkerExit(w, completedAbruptly);
    }
}

接下来我们用文字来说明一下执行任务这个方法的具体逻辑和流程。

  1. 首先在方法一进来,就执行了w.unlock(),这是为了将AQS的状态改为0,因为只有getState() >= 0的时候,线程才可以被中断
  2. 判断firstTask是否为空,为空则通过getTask()获取任务,不为空接着往下执行
  3. 判断是否符合中断状态,符合的话设置中断标记
  4. 执行beforeExecute(),task.run(),afterExecute()方法
  5. 任何一个出异常都会导致任务执行的终止;进入processWorkerExit来退出任务
  6. 正常执行的话会接着回到步骤2

runWorker.jpg


getTask() 

private Runnable getTask() {

    boolean timedOut = false; //标志是否获取任务超时
      ​
    //死循环
    for (;;) {
        int c = ctl.get();    //获取线程池的控制状态
        int rs = runStateOf(c);    //获取线程池的runState
      ​
        /*
         *判断线程池的状态,同时出现以下两种情况
         *    1、runState大于等于SHUTDOWN状态
         *    2、runState大于等于STOP或者阻塞队列为空
         *将会通过CAS操作,进行workerCount-1并返回null
         */
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
      ​
        int wc = workerCountOf(c);    //获取线程池的workerCount(线程数)

        /*
         *allowCoreThreadTimeOut:是否允许core Thread超时,默认false
         *workerCount是否大于核心核心线程池
         */
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
      ​
        /*
         *同时出现下面2种情况
         *    1、wc大于maximumPoolSize或者已超时
         *    2、队列不为空时保证至少有一个任务
         */
        if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
            /*
             *通过CAS操作,workerCount-1
             *能进行-1操作,证明wc大于maximumPoolSize或者已经超时
             */
            if (compareAndDecrementWorkerCount(c))
                //-1操作成功,返回null
                return null;
            //-1操作失败,继续循环
            continue;
        }
      ​
        try {
            /*
             *wc(线程池中线程数)大于核心线程池,执行poll方法
             *小于核心线程池,执行take方法
             */
            Runnable r = timed ?
                            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                            workQueue.take();
            //判断任务不为空返回任务
            if (r != null)
                return r;
            //获取一段时间没有获取到,获取超时
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

还是文字解说一下上面的代码逻辑和流程:

  1. 获取线程池控制状态和runState,判断线程池是否已经关闭或者正在关闭,是的话则workerCount-1操作返回null
  2. 获取workerCount判断是否大于核心线程池
  3. 判断workerCount是否大于最大线程池数目或者已经超时,是的话workerCount-1,-1成功则返回null,不成功则回到步骤1重新继续
  4. 判断workerCount是否大于核心线程池,大于则用poll方法从队列获取任务,否则用take方法从队列获取任务
  5. 判断任务是否为空,不为空则返回获取的任务,否则回到步骤1重新继续

getTask.jpg


processWorkerExit(Worker w, boolean completedAbruptly) 

明显的,在执行任务当中,会去获取任务进行执行,那既然是执行任务,肯定就会有执行完或者出现异常中断执行的时候,那这时候肯定也会有相对应的操作,至于具体操作是怎么样的,我们还是直接去看源码最实际。

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    /*
     *completedAbruptly:在runWorker出现,代表是否突然完成的意思;也就是在执行任务过程当中出现异常,就会突然完成,传true
     *    如果是突然完成,需要通过CAS操作,workerCount-1
     *    不是突然完成,则不需要-1,因为getTask方法当中已经-1
     *下面的代码注释貌似与代码意思相反了
     */
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();
      ​
    final ReentrantLock mainLock = this.mainLock;   //获取当前Worker的重入锁
    mainLock.lock();   //加锁
    try {
        //线程池统计的完成任务数completedTaskCount加上worker当中完成的任务数
        completedTaskCount += w.completedTasks;
        workers.remove(w);   //从HashSet<Worker>中移除当前工作线程worker
    } finally {
        mainLock.unlock();   //释放锁
    }
      ​
    //因为上述操作是释放任务或线程,所以会判断线程池状态,尝试终止线程池
    tryTerminate();
      ​
    int c = ctl.get();   //获取线程池的控制状态
    //判断runState是否小于STOP,即是RUNNING或者SHUTDOWN
    //如果是RUNNING或者SHUTDOWN,代表没有成功终止线程池
    if (runStateLessThan(c, STOP)) {

         //如若不是突然完成,代表已经没有任务可获取完成,因为getTask当中是while循环
        if (!completedAbruptly) {
             //allowCoreThreadTimeOut:是否允许core thread超时,默认false(min-默认是corePoolSize)
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;

            //允许core thread超时并且队列不为空
            //    min为0,即允许core thread超时,这样就不需要维护核心核心线程池了
            //    如果workQueue不为空,则至少保持一个线程存活
            if (min == 0 && !workQueue.isEmpty())
                min = 1;

            //如果workerCount大于min,则表示满足所需,可以直接返回
            if (workerCountOf(c) >= min)
                return; 
        }
        
        //到这里说明是突然完成:添加一个空任务的worker线程--这里我也不太理解
        addWorker(null, false);
    }
}
  1. 首先判断线程是否突然终止,如果是突然终止,通过CAS,workerCount-1
  2. 统计线程池完成任务数,并将worker从workers当中移除
  3. 判断线程池状态,尝试终止线程池
  4. 线程池没有成功终止
    • 判断是否突然完成任务,不是则进行下一步,是则进行第三步
    • 如允许核心线程超时,队列不为空,则至少保证一个线程存活
    • 添加一个空任务的worker线程

reject(Runnable command) 

就是调用策略类的 rejectExecution() 方法

final void reject(Runnable command) {
    handler.rejectedExecution(command, this);
}

 

7、部分其他方法

interruptIdleWorkers(boolean onlyOne)

中断 workers 中的 worker.thread

// 参数omplyOne=true,表示只中断1个worker

private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();   //获取线程池的mainLock
    try {
        // 遍历workers集合;对没有中断的worker.thread,获取worker的锁,然后对其中断
        for (Worker w : workers) {
            Thread t = w.thread;  //获取worker对应的thread
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();   //释放mainLock锁
    }
}

awaitTermination(long timeout, TimeUnit unit) 

等待线程池 变成 Termination

// 这个方法在本类中,没有被其他方法调用

public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();  // 获取mainLock锁
    try {
        // 死循环
        for (;;) {
            // 如果线程池状态至少是TERMINATED(其实TERMINATED已经是最大了)
            if (runStateAtLeast(ctl.get(), TERMINATED))
                return true;
            // 状态不满足时,如果还有剩余时间,就接着等待;如果超时,就返回false
            if (nanos <= 0)
                return false;
            nanos = termination.awaitNanos(nanos);
        }
    } finally {
        mainLock.unlock();   //释放锁
    }
}

decrementWorkerCount() 

死循环+CAS ,工作线程个数-1

private void decrementWorkerCount() {
    do {
    } while (! compareAndDecrementWorkerCount(ctl.get()));
}

 ensurePrestart() 

如果工作线程个数 < corePoolSize,就往workers中添加空任务线程

void ensurePrestart() {
    int wc = workerCountOf(ctl.get());
    if (wc < corePoolSize)
        addWorker(null, true);
    else if (wc == 0)
        addWorker(null, false);
}

getCompletedTaskCount() 

注意:线程池已完成任务数 = 当前线程池已完成任务数 + 线程池中的工作线程完成的任务数

public long getCompletedTaskCount() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();  //mainLock加锁
    try {
        long n = completedTaskCount;
        for (Worker w : workers)
            n += w.completedTasks;
        return n;
    } finally {
        mainLock.unlock();
    }
}

 

参考资料:

Java并发之线程池ThreadPoolExecutor源码分析学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值