线程池源码——execute,runWorker

本文详细分析了`ThreadPoolExecutor`的工作原理,包括线程池的创建、任务提交流程、线程管理和任务调度策略。重点讲解了`execute()`方法内部如何决定创建新线程、使用工作队列或执行拒绝策略,以及`addWorker()`方法中线程的创建与启动。通过对源码的剖析,揭示了线程池在高并发场景下的效率和稳定性。
摘要由CSDN通过智能技术生成
提交任务的入口
    //command 可以是普通的Runnable 实现类,也可以是 FutureTask
    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最新值赋值给c,ctl :高3位 表示线程池状态,低位表示当前线程池线程数量。
        int c = ctl.get();
        //workerCountOf(c) 获取出当前线程数量
        //条件成立:表示当前线程数量小于核心线程数,此次提交任务,直接创建一个新的worker,对应线程池中多了一个新的线程。
        if (workerCountOf(c) < corePoolSize) {
            //addWorker 即为创建线程的过程,会创建worker对象,并且将command作为firstTask
            //core == true 表示采用核心线程数量限制  false表示采用 maximumPoolSize
            if (addWorker(command, true))
                //创建成功后,直接返回。addWorker方法里面会启动新创建的worker,将firstTask执行。
                return;

            //执行到这条语句,说明addWorker一定是失败了...
            //有几种可能呢??
            //1.存在并发现象,execute方法是可能有多个线程同时调用的,当workerCountOf(c) < corePoolSize成立后,
            //其它线程可能也成立了,并且向线程池中创建了worker。这个时候线程池中的核心线程数已经达到,所以...
            //2.当前线程池状态发生改变了。 RUNNING SHUTDOWN STOP TIDYING TERMINATION
            //当线程池状态是非RUNNING状态时,addWorker(firstTask!=null, true|false) 一定会失败。
            //SHUTDOWN 状态下,也有可能创建成功。前提 firstTask == null 而且当前 queue  不为空。特殊情况。
            c = ctl.get();
        }


        //执行到这里有几种情况?
        //1.当前线程数量已经达到corePoolSize
        //2.addWorker失败..

        //条件成立:说明当前线程池处于running状态,则尝试将 task 放入到workQueue中。
        if (isRunning(c) && workQueue.offer(command)) {
            //执行到这里,说明offer提交任务成功了..

            //再次获取ctl保存到recheck。
            int recheck = ctl.get();

            //条件一:! isRunning(recheck) 成立:说明你提交到队列之后,线程池状态被外部线程给修改 比如:shutdown() shutdownNow()
            //这种情况 需要把刚刚提交的任务删除掉。
            //条件二:remove(command) 有可能成功,也有可能失败
            //成功:提交之后,线程池中的线程还未消费(处理)
            //失败:提交之后,在shutdown() shutdownNow()之前,就被线程池中的线程 给处理。
            if (! isRunning(recheck) && remove(command))
                //提交之后线程池状态为 非running 且 任务出队成功,走个拒绝策略。
                reject(command);

            //有几种情况会到这里?
            //1.当前线程池是running状态(这个概率最大)
            //2.线程池状态是非running状态 但是remove提交的任务失败.

            //担心 当前线程池是running状态,但是线程池中的存活线程数量是0,这个时候,如果是0的话,会很尴尬,任务没线程去跑了,
            //这里其实是一个担保机制,保证线程池在running状态下,最起码得有一个线程在工作。
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }

        //执行到这里,有几种情况?
        //1.offer失败
        //2.当前线程池是非running状态

        //1.offer失败,需要做什么? 说明当前queue 满了!这个时候 如果当前线程数量尚未达到maximumPoolSize的话,会创建新的worker直接执行command
        //假设当前线程数量达到maximumPoolSize的话,这里也会失败,也走拒绝策略。

        //2.线程池状态为非running状态,这个时候因为 command != null addWorker 一定是返回false。
        else if (!addWorker(command, false))
            reject(command);

    }

添加工作线程

从这里就可以看出线程是不区分核心不核心的,知识一个判断而已

成功:创建worker 成功 并且 启动成功

失败:线程数量判断、线程池状态、worker创建失败、worker启动失败

    //w 就是启动worker
    final void runWorker(Worker w) {
        //wt == w.thread
        Thread wt = Thread.currentThread();
        //将初始执行task赋值给task
        Runnable task = w.firstTask;
        //清空当前w.firstTask引用
        w.firstTask = null;
        //这里为什么先调用unlock? 就是为了初始化worker state == 0 和 exclusiveOwnerThread ==null
        w.unlock(); // allow interrupts

        //是否是突然退出,true->发生异常了,当前线程是突然退出,回头需要做一些处理
        //false->正常退出。
        boolean completedAbruptly = true;

        try {
            //条件一:task != null 指的就是firstTask是不是null,如果不是null,直接执行循环体里面。
            //条件二:(task = getTask()) != null   条件成立:说明当前线程在queue中获取任务成功,getTask这个方法是一个会阻塞线程的方法
            //getTask如果返回null,当前线程需要执行结束逻辑。
            while (task != null || (task = getTask()) != null) {
                //worker设置独占锁 为当前线程
                //为什么要设置独占锁呢?shutdown时会判断当前worker状态,根据独占锁是否空闲来判断当前worker是否正在工作。
                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

                //条件一:runStateAtLeast(ctl.get(), STOP)  说明线程池目前处于STOP/TIDYING/TERMINATION 此时线程一定要给它一个中断信号
                //条件一成立:runStateAtLeast(ctl.get(), STOP)&& !wt.isInterrupted()
                //上面如果成立:说明当前线程池状态是>=STOP 且 当前线程是未设置中断状态的,此时需要进入到if里面,给当前线程一个中断。

                //假设:runStateAtLeast(ctl.get(), STOP) == false
                // (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)) 在干吗呢?
                // Thread.interrupted() 获取当前中断状态,且设置中断位为false。连续调用两次,这个interrupted()方法 第二次一定是返回false.
                // runStateAtLeast(ctl.get(), STOP) 大概率这里还是false.
                // 其实它在强制刷新当前线程的中断标记位 false,因为有可能上一次执行task时,业务代码里面将当前线程的中断标记位 设置为了 true,且没有处理
                // 这里一定要强制刷新一下。不会再影响到后面的task了。
                //假设:Thread.interrupted() == true  且 runStateAtLeast(ctl.get(), STOP)) == true
                //这种情况有发生几率么?
                //有可能,因为外部线程在 第一次 (runStateAtLeast(ctl.get(), STOP) == false 后,有机会调用shutdown 、shutdownNow方法,将线程池状态修改
                //这个时候,也会将当前线程的中断标记位 再次设置回 中断状态。
                if ((runStateAtLeast(ctl.get(), STOP) ||
                        (Thread.interrupted() &&
                                runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                    wt.interrupt();


                try {
                    //钩子方法,留给子类实现的
                    beforeExecute(wt, task);
                    //表示异常情况,如果thrown不为空,表示 task运行过程中 向上层抛出异常了。
                    Throwable thrown = null;
                    try {
                        //task 可能是FutureTask 也可能是 普通的Runnable接口实现类。
                        //如果前面是通过submit()提交的 runnable/callable 会被封装成 FutureTask。
                        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;
                    //更新worker完成任务数量
                    w.completedTasks++;

                    //worker处理完一个任务后,会释放掉独占锁
                    //1.正常情况下,会再次回到getTask()那里获取任务  while(getTask...)
                    //2.task.run()时内部抛出异常了..
                    w.unlock();
                }
            }

            //什么情况下,会来到这里?
            //getTask()方法返回null时,说明当前线程应该执行退出逻辑了。
            completedAbruptly = false;
        } finally {

            //task.run()内部抛出异常时,直接从 w.unlock() 那里 跳到这一行。
            //正常退出 completedAbruptly == false
            //异常退出 completedAbruptly == true
            processWorkerExit(w, completedAbruptly);
        }
    }

runWorker start会调用worker的run方法

    //firstTask 可以为null,表示启动worker之后,worker自动到queue中获取任务.. 如果不是null,则worker优先执行firstTask
    //core 采用的线程数限制 如果为true 采用 核心线程数限制  false采用 maximumPoolSize线程数限制.

    //返回值总结:
    //true 表示创建worker成功,且线程启动

    //false 表示创建失败。
    //1.线程池状态rs > SHUTDOWN (STOP/TIDYING/TERMINATION)
    //2.rs == SHUTDOWN 但是队列中已经没有任务了 或者 当前状态是SHUTDOWN且队列未空,但是firstTask不为null
    //3.当前线程池已经达到指定指标(coprePoolSize 或者 maximumPoolSIze)
    //4.threadFactory 创建的线程是null
    private boolean addWorker(Runnable firstTask, boolean core) {
        //自旋 判断当前线程池状态是否允许创建线程的事情。
        retry:
        for (;;) {
            //获取当前ctl值保存到c
            int c = ctl.get();
            //获取当前线程池运行状态 保存到rs中
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.

            //条件一:rs >= SHUTDOWN 成立:说明当前线程池状态不是running状态
            //条件二:前置条件,当前的线程池状态不是running状态  ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())
            //rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()
            //表示:当前线程池状态是SHUTDOWN状态 & 提交的任务是空,addWorker这个方法可能不是execute调用的。 & 当前任务队列不是空
            //排除掉这种情况,当前线程池是SHUTDOWN状态,但是队列里面还有任务尚未处理完,这个时候是允许添加worker,但是不允许再次提交task。
            if (rs >= SHUTDOWN &&
                    ! (rs == SHUTDOWN &&
                            firstTask == null &&
                            ! workQueue.isEmpty()))
                //什么情况下回返回false?
                //线程池状态 rs > SHUTDOWN
                //rs == SHUTDOWN 但是队列中已经没有任务了 或者 rs == SHUTDOWN 且 firstTask != null
                return false;

            //上面这些代码,就是判断 当前线程池状态 是否允许添加线程。


            //内部自旋 获取创建线程令牌的过程。
            for (;;) {
                //获取当前线程池中线程数量 保存到wc中
                int wc = workerCountOf(c);

                //条件一:wc >= CAPACITY 永远不成立,因为CAPACITY是一个5亿多大的数字
                //条件二:wc >= (core ? corePoolSize : maximumPoolSize)
                //core == true ,判断当前线程数量是否>=corePoolSize,会拿核心线程数量做限制。
                //core == false,判断当前线程数量是否>=maximumPoolSize,会拿最大线程数量做限制。
                if (wc >= CAPACITY ||
                        wc >= (core ? corePoolSize : maximumPoolSize))
                    //执行到这里,说明当前无法添加线程了,已经达到指定限制了
                    return false;

                //条件成立:说明记录线程数量已经加1成功,相当于申请到了一块令牌。
                //条件失败:说明可能有其它线程,修改过ctl这个值了。
                //可能发生过什么事?
                //1.其它线程execute() 申请过令牌了,在这之前。导致CAS失败
                //2.外部线程可能调用过 shutdown() 或者 shutdownNow() 导致线程池状态发生变化了,咱们知道 ctl 高3位表示状态
                //状态改变后,cas也会失败。
                if (compareAndIncrementWorkerCount(c))
                    //进入到这里面,一定是cas成功啦!申请到令牌了
                    //直接跳出了 retry 外部这个for自旋。
                    break retry;

                //CAS失败,没有成功的申请到令牌
                //获取最新的ctl值
                c = ctl.get();  // Re-read ctl
                //判断当前线程池状态是否发生过变化,如果外部在这之前调用过shutdown. shutdownNow 会导致状态变化。
                if (runStateOf(c) != rs)
                    //状态发生变化后,直接返回到外层循环,外层循环负责判断当前线程池状态,是否允许创建线程。
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }


        //表示创建的worker是否已经启动,false未启动  true启动
        boolean workerStarted = false;
        //表示创建的worker是否添加到池子中了 默认false 未添加 true是添加。
        boolean workerAdded = false;

        //w表示后面创建worker的一个引用。
        Worker w = null;
        try {
            //创建Worker,执行完后,线程应该是已经创建好了。
            w = new Worker(firstTask);

            //将新创建的worker节点的线程 赋值给 t
            final Thread t = w.thread;

            //为什么要做 t != null 这个判断?
            //为了防止ThreadFactory 实现类有bug,因为ThreadFactory 是一个接口,谁都可以实现。
            //万一哪个 小哥哥 脑子一热,有bug,创建出来的线程 是null、、
            //Doug lea考虑的比较全面。肯定会防止他自己的程序报空指针,所以这里一定要做!
            if (t != null) {
                //将全局锁的引用保存到mainLock
                final ReentrantLock mainLock = this.mainLock;
                //持有全局锁,可能会阻塞,直到获取成功为止,同一时刻 操纵 线程池内部相关的操作,都必须持锁。
                mainLock.lock();
                //从这里加锁之后,其它线程 是无法修改当前线程池状态的。
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    //获取最新线程池运行状态保存到rs中
                    int rs = runStateOf(ctl.get());

                    //条件一:rs < SHUTDOWN 成立:最正常状态,当前线程池为RUNNING状态.
                    //条件二:前置条件:当前线程池状态不是RUNNING状态。
                    //(rs == SHUTDOWN && firstTask == null)  当前状态为SHUTDOWN状态且firstTask为空。其实判断的就是SHUTDOWN状态下的特殊情况,
                    //只不过这里不再判断队列是否为空了
                    if (rs < SHUTDOWN ||
                            (rs == SHUTDOWN && firstTask == null)) {
                        //t.isAlive() 当线程start后,线程isAlive会返回true。
                        //防止脑子发热的程序员,ThreadFactory创建线程返回给外部之前,将线程start了。。
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();

                        //将咱们创建的worker添加到线程池中。
                        workers.add(w);
                        //获取最新当前线程池线程数量
                        int s = workers.size();
                        //条件成立:说明当前线程数量是一个新高。更新largestPoolSize
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        //表示线程已经追加进线程池中了。
                        workerAdded = true;
                    }
                } finally {
                    //释放线程池全局锁。
                    mainLock.unlock();
                }
                //条件成立:说明 添加worker成功
                //条件失败:说明线程池在lock之前,线程池状态发生了变化,导致添加失败。
                if (workerAdded) {
                    //成功后,则将创建的worker启动,线程启动。
                    t.start();
                    //启动标记设置为true
                    workerStarted = true;
                }
            }

        } finally {
            //条件成立:! workerStarted 说明启动失败,需要做清理工作。
            if (! workerStarted)
                //失败时做什么清理工作?
                //1.释放令牌
                //2.将当前worker清理出workers集合
                addWorkerFailed(w);
        }

        //返回新创建的线程是否启动。
        return workerStarted;
    }
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        //持有线程池全局锁,因为操作的是线程池相关的东西。
        mainLock.lock();
        try {
            //条件成立:需要将worker在workers中清理出去。
            if (w != null)
                workers.remove(w);
            //将线程池计数恢复-1,前面+1过,这里因为失败,所以要-1,相当于归还令牌。
            decrementWorkerCount();
            //回头讲,shutdown shutdownNow再说。
            tryTerminate();
        } finally {
            //释放线程池全局锁。
            mainLock.unlock();
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值