看不懂线程池源码?ThreadPoolExecutor核心源码这样实现

一文带你看懂线程池源码?ThreadPoolExecutor核心源码竟是这样实现!

一句话了解线程池的工作原理

  • ThreadPoolExecutor将任务执行委托给Worker执行
  • ThreadPoolExecutor负责创建和销毁Worker

相关图示

线程池相关类图

在这里插入图片描述

简易流程图

在这里插入图片描述

详尽流程图

在这里插入图片描述

核心属性

// 存储线程池的状态,高3位表示线程池状态,低29位表示worker数量
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3; // 记录表示wirker数量的bit位数,供移位使用
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;    // 记录worker的数量

    // runState is stored in the high-order bits 线程池状态
    // 将 -1 移动到ctl的高3位(高3位111) 表示运行中
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 表示线程池已经关闭,不接收新任务,但能处理已添加的任务 高三位000
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    // 表示线程池暂停,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务 高三位001
    private static final int STOP       =  1 << COUNT_BITS;
    // 当所有的任务已终止,ctl记录的任务数量为0 线程池就会变成TIDYING状态。高三位010
    // 当线程池变为TIDYING状态时,会执行钩子函数terminated(),默认为空实现,可以由用户自定义实现
    // 状态切换:当线程池在shutdown状态下,阻塞队列为null 且线程池中执行的任务也为null时,就会有shutdown -> tidying
    // 当线程池在stop状态下,阻塞队列为null 线程池中执行的任务为null时,就会由 stop -> tidying
    private static final int TIDYING    =  2 << COUNT_BITS;
    // 线程池彻底终止 就成为TERMINATED状态 高三位011
    // 进入terminated条件:
    // 1) 线程池不是running状态
    // 2) 线程池不是tidying 或 terminated状态
    // 3) 如果线程池状态是shutdown 并且 workerQueue为空
    // 4) workerCount为0
    // 5) 设置tidying状态成功
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    // c & ~CAPACITY 将线程池的workerCount部分剔除掉 获取运行状态信息
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // c & CAPACITY 获取线程池的workerCount数量
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    // 由线程池的运行状态 和 workerCount 进行或操作 获取到完整的线程池控制信息
    private static int ctlOf(int rs, int wc) { return rs | wc; }

构造方法

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

execute()方法

public void execute(Runnable command) {
        // 传入的Runnable为null 抛出异常
        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.
         * 如果当前正在运行的线程少于corePoolSize线程,则尝试创建一个新的线程去处理
         * 第一个任务
         *
         * 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.
         * 如果当前task可以成功进入队列,那么我们仍然需要再次检查是否应该创建新的线程(因为可能现有的线程上次检查之后死掉了)
         * 因此,我们需要重新检查状态
         * 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.
         * 如果我们不能把这个task放入队列,那么我们尝试创建一个新的线程,如果创建失败,则需要考虑拒绝该任务
         */
        // 获取线程池状态
        int c = ctl.get();
        // worker数量比核心线程数小,直接创建worker执行任务
        if (workerCountOf(c) < corePoolSize) {
            // 增加一个工作线程 处理command任务
            if (addWorker(command, true))
                return;
            // 获取线程池控制状态
            c = ctl.get();
        }
        // 判断线程池处于运行态 并且 worker数量超过核心线程数,任务直接进入队列
        if (isRunning(c) && workQueue.offer(command)) {
            // 再次获取线程池控制状态进行再次检查
            int recheck = ctl.get();
            // 如果线程池已经不处于运行状态 则将任务拒绝
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 为什么需要判断0值,主要是线程池构造方法中,核心线程允许为0
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 任务不可以放入队列 则创建线程
        else if (!addWorker(command, false))
            // 如果无法继续创建线程 则拒绝任务
            reject(command);
    }

addWorker()

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        /*
        循环判断是否可以创建新的工作线程 退出循环的条件:
        1:可以创建线程 将线程数量WorkerCount++  跳出循环
        2:线程池的生存状态不是可运行态 直接return false
        */
        for (;;) {
            int c = ctl.get();  // 获取线程池控制状态
            int rs = runStateOf(c); // 从控制状态中获取线程池生存状态

            // Check if queue empty only if necessary.
            // rs >= SHUTDOWN 代表线程池不处于可运行态 直接返回false 代表无法添加新的任务
            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
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建一个工作线程 将firstTask丢给该线程
            w = new Worker(firstTask);
            // 获取工作线程
            final Thread t = w.thread;
            // 如果工作线程不为null
            if (t != null) {
                // 获取lock锁 保证后续代码的线程安全
                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 : 线程池是可运行态
                    // 如果rs是RUNNING状态或者rs是SHUTDOWN状态并且firstTask为null,向线程池中添加线程。
                    // 因为在SHUTDOWN时不会在添加新的任务,但还是会执行workQueue中的任务
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 此时线程应该还未启动 在后面的start时才启动 如果此时线程就已经启动 则直接抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 将当前工作线程加入工作线程集合中
                        workers.add(w);
                        // 获取工作线程的数量
                        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()构造

Worker是ThreadPoolExecutor的内部类,继承了AbstractQueuedSynchronizer类实现了Runnable接口,扩展了AQS的功能,主要对线程池的Thread进行封装,使线程可以不必频繁的创建和销毁,实现的具体原理是如果有任务就一直进行while()循环,否则判断是否需要关闭线程。(该逻辑在getTask()中实现)

Worker(Runnable firstTask) {
            // 设置state为-1 禁止中断,直到runWorker
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            // 创建一个线程 将worker本身作为Runnable任务对象传给线程工厂 而不是将firstTask传给线程工厂
            this.thread = getThreadFactory().newThread(this);
        }

Worker的run()

public void run() {
            // 线程执行会调用的run方法
            runWorker(this);
        }

runWorker()

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        // 获取worker对象的firstTask
        Runnable task = w.firstTask;
        // 将worker.firstTask置空
        w.firstTask = null;
        // 允许中断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            /*
             保证线程不会停止 会无限的获取任务 进行执行 防止线程任务结束就停止 减少创建和销毁线程的开销
             因为Java的线程采用KLT模型(用户线程和内核线程一一映射) 所以创建线程和销毁线程都需要从用户态切换到内核态
             非常耗费系统资源
            */

            // 如果当前处理的task不为null  或者可以从阻塞队列中取到任务
            // 在getTask中如果没有获取到任务 则会将workerCount-- 但是并不会直接减少worker的数量
            // 留在while跳出后,执行processWorkerExit() 关闭worker
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                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方法 如果出现了异常直接抛出
                        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 = null;
                    // 将完成任务的数量++
                    w.completedTasks++;
                    // 释放锁
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            // 从while循环中退出 证明当前线程需要被关闭
            processWorkerExit(w, completedAbruptly);
        }
    }

getTask()

private Runnable getTask() {
        // 表示上次从阻塞队列中获取任务是否超时
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            // 获取线程池控制状态
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            /*
             * 如果线程池状态rs >= SHUTDOWN,也就是非RUNNING状态,再进行以下判断:
             * 1. rs >= STOP,线程池是否正在stop;
             * 2. 阻塞队列是否为空。
             * 如果以上条件满足,则将workerCount减1并返回null。
             * 因为如果当前线程池状态的值是SHUTDOWN或以上时,不允许再向阻塞队列中添加任务。
             */
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            // 获取workerCount的值
            int wc = workerCountOf(c);

            // Are workers subject to culling?
            // 判断当前是否需要超时关闭
            // 判断的标准就是:核心线程是否允许超时关闭 和 当前的线程数量超过核心线程数量
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            /*
            * 出现 wc > maximumPoolSize的情况是因为可能此方法执行的同时执行了setMaximumPoolSize方法
            * timed && timedOut 如果为true 表示当前操作需要进行超时控制,并且上次从阻塞队列中获取任务时发生了超时
            * 接下来判断,如果有效线程数量大于1,或者阻塞队列是空的,那么尝试将workerCount减1;
            * 如果减1失败,则返回重试。
            * 如果wc == 1时,也就说明当前线程是线程池中唯一的一个线程了。
            * */
            // 如果当前线程数量 > 线程池中允许的最大线程数量 或者 需要进行超时关闭线程 并且 wc的数量大于1 或者阻塞队列为null
            // 需要减少一个worker的数量
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // 如果减少worker数量成功 则直接return null
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                // 如果需要进行超时关闭线程 则从workQueue中等待keepAliveTime时间后取出任务 如果没有取到就返回null
                // 如果不需要进行超时关闭线程 则使用take() 一直阻塞获取任务
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                // 如果获取到的任务不为null 则直接返回任务
                // 如果没有获取到任务 则继续循环
                if (r != null)
                    return r;
                timedOut = true;    // 设置允许超时退出
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

processWorkerExit()

private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            // 将当前worker从集合中移除
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        // 尝试关闭线程
        tryTerminate();

        // 获取线程工作状态
        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                // 判断线程池允许保留的最少线程数量是多少
                // 如果allowCoreThreadTimeOut设置为true 代表用户允许核心线程被超时回收
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                // 如果允许的最少线程数量为0 但是阻塞队列并不为null 仍有任务需要处理 则将min设置为1
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                // 如果线程池现存的worker数量 >= min worker数量 直接return
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 如果当前worker数量小于系统要求的min worker数量 则会再创建一个worker
            addWorker(null, false);
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值