源码分析--ThreadPoolExecutor(二)

16 篇文章 0 订阅

常用方法

核心方法:execute

// command 是一个 Runnable 对象,也就是用户提交执行的任务
public void execute(Runnable command) {
    // 提交的任务为空时抛出异常
    if (command == null)
        throw new NullPointerException();

    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    // 获取当前 ctl (存有线程池状态和线程数量)
    int c = ctl.get();

    // 若当前工作线程数量小于核心池大小(coolPoolSize)
    // 则在核心池中新增一个工作线程,并将该任务交给这个线程执行
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        // 重新获取(存在并发可能)
        c = ctl.get();
    }

    // 若执行到这里,表示池中线程数量 >= corePoolSize,或者上面 addWorker 失败
    // 若线程池处于 RUNNING 状态,并且该任务(command)成功添加到任务队列
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次获取 ctl 值
        int recheck = ctl.get();
        // 若线程池不是运行状态,则要把上面添加的任务从队列中移除并执行拒绝策略
        //(可理解为“回滚”操作)
        if (! isRunning(recheck) && remove(command))
            // 执行拒绝策略           
            reject(command);
        // 若此时池中没有线程,则新建一个
        // PS: 这里是防止任务提交后,池中没有存活的线程了
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }

    // 根据上述代码分析,若执行到这里,可分为以下两种情况:
    // ① 线程池不是 RUNNING 状态;
    // ② 线程池处于 RUNNING 状态,且实际线程数量 workCount >= corePoolSize,
    //   并且,添加到 workQueue 失败(已满)
    // 此时,则需要和 maximumPoolSize 进行比较,
    //   若 workCount <= maximumPoolSize, 则新建一个线程去执行该任务;
    //   否则,即 workCount > maximumPoolSize (饱和),则执行拒绝策略
    else if (!addWorker(command, false))
        // 执行拒绝策略
        reject(command);
}

该方法描述的就是一个任务提交到线程池的流程,主要执行逻辑如下:

1、若正在运行的线程数少于 corePoolSize,则创建一个新的线程,并将传入的任务(command)作为它的第一个任务执行。
2、若运行的线程数不小于 corePoolSize,则将新来的任务添加到任务队列(workQueue)。若入队成功,仍需再次检查是否需要增加一个线程(上次检查之后现有的线程可能死了,或者进入该方法时线程池 SHUTDOWN 了,此时需要执行回滚);若池中没有线程则新建一个(确保 SHUTDOWN 状态也能执行队列中的任务)。
3、若任务不能入队(队列已满),则创建新的线程并执行任务,若失败(超过 maximumPoolSize),则表示线程池关闭或者已经饱和,因此拒绝该任务。

在线程池中,ctl 贯穿在线程池的整个生命周期中,它是一个原子类,主要作用是用来保存线程数量和线程池的状态。

内部类Worker及其方法:

// 继承自 AQS,且实现了 Runnable 接口
private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    /** Thread this worker is running in.  Null if factory fails. */
    final Thread thread;
    /** Initial task to run.  Possibly null. */
    // 运行的第一个任务,可能为空
    Runnable firstTask;
    /** Per-thread task counter */
    volatile long completedTasks;
    /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        // 初始化 thread
        this.thread = getThreadFactory().newThread(this);
    }
    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }
    // 其他一些 AQS 相关的方法不再一一列举
}

addWorker 方法:
在execute方法里可以看到这个方法,如果工作线程数小于核心线程数的话,会调用 addWorker,顾名思义,其实就是要创建一个工作线程。

// firstTask: 第一个任务,可为空
// core: 是否为核心池,true 是,false 为最大池
private boolean addWorker(Runnable firstTask, boolean core) {
    // 该循环的主要作用就是增加 workCount 计数,增加成功后再新增 Worker 对象
    retry://goto 语句,避免死循环
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        /*
         * rs >= SHUTDOWN 表示线程池不再接受新的任务
         * 该判断条件分为以下三种:
         *   ① 线程池处于 STOP, TYDING 或 TERMINATED 状态;
         *   ② 线程池处于 SHUTDOWN 状态,且 firstTask 不为空;
         *   ③ 线程池处于 SHUTDOWN 状态,且 workQueue 为空
         * 满足任一条件即返回 false.
         */
        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {//自旋
            int wc = workerCountOf(c);
            // 超出最大容量 CAPACITY,或者超出初始设置的核心池/最大池数量,则返回 false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // CAS 方式增加 ctl 的 workerCount 数量(该循环的主要目的)
            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
        }
    }
    // 标记 Worker 是否启动、是否添加成功
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 将 firstTask 封装成 Worker 对象
        w = new Worker(firstTask);
        // 获取 thread 对象 t
        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());
                // 若线程池状态小于 SHUTDOWN,即为 RUNNING 状态;
                // 或者为 SHUTDOWN 状态,且 firstTask 为空,
                //   表示不再接受新的任务,但会继续执行队列中的任务
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    // 添加到工作线程集合(HashSet)
                    workers.add(w);
                    // 更新最大计数
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 标记 Worker 添加成功
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 若成功添加到工作线程集合,则启动线程执行任务
            if (workerAdded) {
                // 启动线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // Worker 启动失败,执行回滚操作
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

addWorker 方法中,如果添加 Worker 并且启动线程失败,则会做失败后的处理。

    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            decrementWorkerCount();
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

runWorker 方法:
这个方法主要做几件事

1、如果 task 不为空,则开始执行 task
2、如果 task 为空,则通过 getTask()再去取任务,并赋值给 task,如果取到的 Runnable 不为空,则执行该任务
3、执行完毕后,通过 while 循环继续 getTask()取任务
4、如果 getTask()取到的任务依然是空,那么整个 runWorker()方法执行完毕

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        //unlock,表示当前 worker 线程允许中断,因为 new Worker 默认的 state=-1,此处是调用
        //Worker 类的 tryRelease()方法,将 state 置为 0,
        //而 interruptIfStarted()中只有 state>=0 才允许调用中断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            //注意这个 while 循环,在这里实现了 [线程复用] // 如果 task 为空,则通过getTask 来获取任务
            while (task != null || (task = getTask()) != null) {
                w.lock(); //上锁,不是为了防止并发执行任务,为了在 shutdown()时不终止正在运行的 worker
                //线程池为 stop 状态时不接受新任务,不执行已经加入任务队列的任务,还中断正在执行的任务
                //所以对于 stop 状态以上是要中断线程的
                //(Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP)确保线程中断标志位为 true 且是 stop 状态以上,接着清除了中断标志
                //!wt.isInterrupted()则再一次检查保证线程需要设置中断标志位
                if ((runStateAtLeast(ctl.get(), STOP) ||
                        (Thread.interrupted() &&
                                runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);//这里默认是没有实现的,在一些特定的场景中我们可以自己继承 ThreadpoolExecutor 自己重写
                    Throwable thrown = null;
                    try {
                        task.run(); //执行任务中的 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,需要再通过 getTask()取) + 记录该 Worker 完成任务数量 + 解锁
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
            //1.将入参 worker 从数组 workers 里删除掉;
            //2.根据布尔值 allowCoreThreadTimeOut 来决定是否补充新的 Worker 进数组workers
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值