Executor多线程框架学习笔记(四):ThreadPoolExecutor源码分析

目录

创建新线程:addWorker

线程的主循环

线程结束:processWorkerExit

ThreadPoolExecutor的状态变迁


ThreadPoolExecutor实例创建之后,在没有调用execute提交任务之前,ThreadPool中是没有线程的,线程的创建是依赖exeute来驱动的。可以说,exeute是ThreadPoolExecutor运行的触发器,所有我选择先从exeute方法开始分析代码。

public void execute(Runnable command) {
  if (command == null)
    throw new NullPointerException();

  int c = ctl.get();

  if (workerCountOf(c) < corePoolSize) { //如果线程数小于 corePoolSize, 创建一个新线程。
    if (addWorker(command, true))
     return;
    c = ctl.get();
  }

  if (isRunning(c) && workQueue.offer(command)) { //如果处于RUNNGIN状态把任务放到队列中
    int recheck = ctl.get();
    if (! isRunning(recheck) && remove(command)) //再次检查线程状态,如果不是RUNNING状态,把任务从队列删除,然后拒绝这个任务
      reject(command);
    else if (workerCountOf(recheck) == 0) //如果线程数为0,创建一个新线程
      addWorker(null, false);
  }
  /*如果运行到这里说明当前不是出于RUNNING状态,或处于RUNNING状态但队列已经被填满
  *尝试创建新的线程执行这个任务,如果失败,拒绝这任务
  */
  else if (!addWorker(command, false))
    reject(command);

}

以上就是exeute代码,它很简单,但其中ctl成员变量比较费解。ctl是AtomicInteger类型,它被用来打包保存ThreadPoolExecutor的状态和线程数。

状态

ThreadPool定义了5状态

  • RUNNING: 接受新提交的任务,执行队列中发任务。
  • SHUTDOWN: 不接受新提交的任务,但仍然会执行队列中的人。
  • STOP: 不接受新提交的任务,不执行队列中的任务,而且会打断正在执行中的任务。
  • TIDYING: 所有的任务都终止了,并且线程数为0,当所有的线程都过渡到TIDYING状态后会调用treminated方法。
  • TERMINATED: treminated方法调用已经完成。

状态之间的转换关系

  • RUNNING --> SHUTDOWN:调用shutdown()
  • (RUNNING或SHUTDOWN) -- > STOP:调用shutdownNow()
  • SHUTDOWN --> TIDYING:队列为空,同时线程数为0
  • TIDYING --> TREMINATED:treminated()执行完成

AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

它初始化时,把状态设置成RUNNING,下面来看看它的结构:

运算状态(run state)

线程数(workerCount)

31 -- 29

28 -- 0

状态位

  • RUNNING:111
  • SHUTDOW:000
  • STOP:001
  • TIDYING:010
  • TREMINATED:011

知道了这些数据的保存方式,把他们取出来,只需要一些简单的位运算就可以了。

状态的大小关系:

  • RUNNING < SHUTDOWN < STOP < TIDYING < TREMINATED,
  • runStateOf(clt.get()) < SHUTDOWN RUNNING状态
  • runStateOf(clt.get()) >= SHUTDOWN 非RUNNING状态

创建新线程:addWorker

ThreadPool把线程封装成Worker对对象,添加worker就是添加线程,addWorker方法做的事情就是添加线程。

private boolean addWorker(Runnable firstTask, boolean core) {
    /*这段代码的作用是确保满足一下条件的任意一个时才创建新线程
   *1.  处于RUNNING 状态, 可以接受新任务,可以继续执行队列中的任务
   *2. 处于SHUTDOWN状态,  队列不是空,且当前没有提交新任务
   */
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&   //非RUNNINGG状态
            ! (rs == SHUTDOWN &&  
               firstTask == null &&  //当前提交的新任务
               ! workQueue.isEmpty())) // 队列不是空
            return false;
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize)) //如果当前调用创建的是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
        }
    }
    //执行到这里表示已经通过检查可以创建新线程,并且线程数已经加1
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            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());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {  //再次检查,确保当前仍然满足允许创建线程的条件
                    if (t.isAlive()) // 确保Thread还没有调用start()
                        throw new IllegalThreadStateException();
                    workers.add(w); //把worker线程放进HashSet中
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();  //启动新线程
                workerStarted = true;
            }
        }
    } finally {

        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

线程的主循环

Worker实现了Runnable接口

private final class Worker extends AbstractQueuedSynchronizer  implements Runnable

//构造方法
Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
}

//创建线程时把Worker实例本身当做线程的Runnable产生,所以当线程启动后,将会调用Worker的run方法。
public void run() {
        runWorker(this);

}

//线程的主循环就在runWorker方法中实现
final void runWorker(Worker w) {

    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;  //如果firstTask!=null, 先执行firstTask
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) { //如果没有firstTask,  从队列中取出一个task, 如果没有取到,退出线程
            w.lock();
        //如果处于状态>=STOP(前面已经讲过状态直接的大小关系), 确保线程处于interrupted状态
       //否则清除线程的interrupted状态
            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; //把当前task置空,这样才能调用getTask从队列里取出任务
                w.completedTasks++;
                w.unlock();
            }
        }

        completedAbruptly = false;

    } finally {
       //正常退出线程 completedAbruptly是true, 异常导致的线程退出为false
        processWorkerExit(w, completedAbruptly);
    }
}

从队列中得到排队的任务

在runWorker主循环中,除了第一次的任务从worker的firsTask(在它不是null的情况下)取之外, 后面每次都是调用getTask从队列中取出一个任务。

下面是getTask的代码分析

private Runnable getTask() {

    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c); //得到当前状态

        // 如果当前状态 > SHUTDOWN 退出线程
    // 如果当前状态 == SHUTDOWN 且 队列为空,退出线程
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();  //减少当前线程数

            return null;

        }
        int wc = workerCountOf(c); //得到当前的线程数
        //线程是否允许超时的条件: 设置允许coreThread超时,或者当前线程数 > corePoolSize
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    //线程退出需要同时满足以下两个条件条件: 
    //1. 当前线程数>maximumPooSize 或 允许超时同时检查到已经超时
    //2. 当前线程数>1 或 队列为空
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c)) //减少当前线程数, 这个方法确保多线程环境下不会过多地结束线程。
                return null;
            continue;

        }

        try {

           //取出一个任务。如果允许超时,调用poll,否则调用take
            Runnable r = timed ?
            workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
            workQueue.take();

            if (r != null)
                return r;

            timedOut = true; //已经超时,运行到这里表明poll超时返回
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

getTask的功能除了取出一个任务以外,它还负责在条件满足的情况下正常地结束一个线程

线程结束:processWorkerExit

private void processWorkerExit(Worker w, boolean completedAbruptly) {

    if (completedAbruptly) // 如果线程是由于异常原因结束的,这里要纠正线程数
        decrementWorkerCount();

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

    try {
        completedTaskCount += w.completedTasks;
        workers.remove(w);  //把线程从HashSet中删除
    } finally {
        mainLock.unlock();
    }

    tryTerminate(); //尝试终止整个ThreadPool

    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {  //如果当前状态<STOP
        if (!completedAbruptly) { //如果不是异常结束
             //计算最小线程数min
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty()) 
                min = 1;
            if (workerCountOf(c) >= min)  //如果当前线程数>=min直接返回
                return; // replacement not needed
        }
        //创建新线程, 条件:
        //当前线程正常结束
        //当前线程异常结束,但当前线程数小于最小线程数
        addWorker(null, false);
    }
}

上面的代码实现了线程的生命周期的管理,线程只有在ThreadPoolExecutor的状态处于RUNNGIN或SHUTDOWN时才可以存在。下面是这两种状态下线程的生存状态:

RUNNING:

  • 允许coreThread超时: 线程空闲(意味着队列为空)时间超过 keepAliveTime, 线程会被结束, 直到线程数为0。
  • 不允许coreThread超时:  线程空闲时间超过 keepAliveTime, 线程会被结束,直到线程数为corePoolSize。

SHUDOWN:

  • 当线程把已经在队列里的所有任务执行完毕后,所有线程都会进入退出流程,最终退出。

ThreadPoolExecutor的状态变迁

前面已经讲过,ThreadPool的状态和线程数被打包方进一个32整数中:

AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

初始化把状态设置成RUNNING, 线程为0

调用shutdown时把状态从RUNNING置为SHUTDOWN,  随后过渡到TIDYING->TREMINATED。

当调用shutdownNow时把状态从(RUNNING 或 SHUTDOWN) 设置为STOP,  随后过渡到TIDYING->TREMINATED。

public void shutdown() {

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

    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);    //只有当前状态<SHUTDOWN时才执行状态设置的动作
        interruptIdleWorkers();  //打断所有空闲的的线程,让这些线程有机会自己结束
        onShutdown(); // 回调方法,默认什么都没做,子类可以覆盖
    } finally {
        mainLock.unlock();
    }

    tryTerminate(); //尝试执行ThreadPool的结束操作

}

shutdownNow和shutdown的操作大致一样,不同的是它把状态设置成STOP,还会返回队列中没有来得及执行的任务list。

tryTerminate方法作用是尝试结束整个ThreadPool, 它不一定会执行真正的结束动作。它在三个地方被调用, worker线程结束时,shudown中,shutdownNow中。

final void tryTerminate() {

    for (;;) {
        int c = ctl.get();

    //满足以下三个条件中的任何一个就立即返回

    //1. 处于RUNNGING状态
    //2. 状态>= TIDYING
    //3. 处于SHUTDOWN状态,且队列不是空
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))

            return;

    //如果处于STOP状态,且线程数不为0,通知一个处于空闲的线程结束自己
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;

        }

    //执行到这里表示目前状态>=SHUTDOWN,线程数已经是0
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { //总有一个线程会运行到这里,把状态置为 TIDYING
                try {
                    terminated(); //调用回调方面,默认什么都没干,子类可以覆盖
                } finally {
                    ctl.set(ctlOf(TERMINATED, 0));  //把状态置为TREMINATED, 自此整个ThreadPool才算终结
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }

}

tryTerminate之所以要在三个地方调用,是为了保证当调用shutdown或shutdownNow之后,总有一个线程会完成最后的终结工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值