线程池原理(三):ThreadPoolExecutor核心方法之execute()方法

1、execute(Runnable command) 方法

     execute() 方法是线程池 ThreadPoolExecutor 中最核心的方法,由前边的 

     AbstractExecutorService 类可以知道 执行 submit() 方法向线程池提交任务时,提交任务

     的操作最终还是由execute() 来完成,如下图所示:

                

      execute() 方法执行时有4种情况,即:

           1)如果当前运行的线程少于核心线程数corePoolSize,则创建新的线程来执行当前提交

                 的任务,执行这一步骤需要获取全局锁

           2)如果当前运行的线程数等于或大于核心线程数corePoolSize,则将当前提交的任务放入

                 BlockingQueue阻塞队列中

           3)如果无法将当前提交的任务放入BlockingQueue(即队列已满),但运行的线程数小于

                最大线程数maximumPoolSize,则创建新的线程来处理任务,执行这一步骤需要获取

                全局锁

           4)如果当前运行的线程数已经到达最大线程数 maximumPoolSize,则调用

                 RejectedExecutionHandler.rejectedExecution() 处里该任务;

                若使用默认的 RejectedExecutionHandler,任务将被拒绝(默认拒绝策略是直接拒

                绝任务)

          execute() 方法执行流程图如下:

                     

          ThreadPoolExecutor 采用上述步骤的设计思路是为了执行execute()方法时,尽量避免

          获取全局锁;当ThreadPoolExecutor 中运行的线程数大于 corePoolSize 时,几乎所有

          的execute() 方法调用都是执行步骤2,步骤2不需要获取全局锁。

          execute() 方法代码如下:

/**
     *
     * 执行给定的任务,这个任务可以在新线程中执行,也可以在线程池中已存在的线程中执行
     *
     * 如果任务不能提交执行,可能是因为这个原因执行程序已关闭或已达到容量,
     * 该任务由当前的{@code RejectedExecutionHandler}处理。
     *
     */
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * 
         * 执行线程任务按3个步骤执行:
         * 1、如果线程池中少于corePoolSize线程运行,尝试启动一个新的线程与给定的命令作为它的第一个任务线程。
         * 对addWorker的调用会自动检查runState和 workerCount,因此通过返回false来防止误报,
         * 因为误报会在不应该添加线程的时候添加线程。
         *
         * 2、如果一个任务可以成功地进入队列,那么我们仍然需要再次检查我们是否应该添加一个线程(因为现有的线程在上次检查后死亡),
         * 或者池在进入这个方法后关闭。因此,我们重新检查状态,并在停止时回滚队列,或者在没有线程时启动一个新线程。
         *
         * 3、如果不能把任务添加到队列中,则尝试添加一个新的线程。如果它失败了,我们知道我们已经关闭或饱和了
         *,因此拒绝任务。
         */
        //重新获取线程数
        int c = ctl.get();
        //1、如果线程池中的线程总数小于设置的核心线程数 corePoolSize,
        //则创建一个新的线程去执行 command
        //一个worker 其实就是一个线程,包含需要执行的任务command,其实任务也是一个线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))//启动新的线程成功(即核心线程没满),则直接结束
                return;
            //重新获取线程数,
            // 若 addWorker 执行失败,那么此时ctl可能被更新了,所以需要获取
            c = ctl.get();
        }
        //核心线程数满了,试着将任务线程放入工作队列
        if (isRunning(c) && workQueue.offer(command)) {//2、线程池处于运行状态且任务队列没有满,任务command入队列成功
            //复查线程池是否是运行状态(预防别人任务关闭线程池)
            int recheck = ctl.get();
            //若线程池非处在运行状态,即线程池关闭了,且任务command 已经位于工作队列中(可以成功从队列中删除,即在进入execute 方法后线程池关闭了)
            //,则把任务 command 交给拒绝策略执行
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)//核心线程数空了,允许核心线程数释放资源,这个是临界情况
                //启动一个新的线程,该线程没有绑定任务,实际中基本不存在这种情况
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//3、线程池已经饱和(即线程数达到最大线程数,工作队列也已经满了)或线程池关闭了,则把该任务交给拒绝策略执行
            reject(command);
    }

   

2、addWorker(Runnable firstTask, boolean core)

      addWorker 主要功能是通过Worker 创建线程并修改线程池工作线程的个数,

      firstTask-- 新线程首先运行的任务(如果没有,则为 null)。
                      worker被创建为一个初始化的first task (在方法execute()中),当少于corePoolSize

                      线程(在这种情况下,我们总是启动一个),或当队列是满的(在这种情况下,我们必

                      须绕过队列)。初始空闲线程通常是通过prestartCoreThread创建的,或者用来替

                      换其他垂死的工作线程。

      core-- 如果为true,则使用corePoolSize作为绑定(即把任务firstTask设置为核心线程,并立

                  即执行),否则maximumPoolSize。(这里使用布尔指示符而不是在检查其他池后,

                  确保读取新的值状态)。

      addWorker 方法代码如下:

private boolean addWorker(Runnable firstTask, boolean core) {
        /**
         * 创建 Worker
         */
        retry:
        /*
         * 先去增加线程池中线程总数
         * 使用循环的原因可能第一次线程池满了,添加不进去,后面第二次进入循环后,线程池有执行结束的工作线程,就可以增加成功了。
         *
         * 判断线程池状态,添加线程数
         */
        for (;;) {
            //获取当前线程池中线程数
            int c = ctl.get();
            //返回线程池是否是运行状态值,
            int rs = runStateOf(c);

            //  仅在必要时检查队列是否为空
            if (rs >= SHUTDOWN && //表示线程池处于非运行状态
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))//若当前线程池状态是 非运行状态 且(若当前是SHUTDOWN 状态 且 firstTask第一个任务为null且工作队列不为空)=false,则添加工作器worker 失败
                                          //若工作队列不为null,则线程池活动的线程数可能会大于核心线程数,若工作队列为null,则会线程数小于或等于核心线程数
                return false;

            //修改(即增加线程的个数)
            for (;;) {
                //获取工作器(每个工作器worker表示一个工作线程)的总数,即当前线程池中线程的总数
                int wc = workerCountOf(c);
                //若当前线程的总数大于设定的最大值 CAPACITY 或大于 构造函数中设定的值(corePoolSize 或 maximumPoolSize),
                //则添加失败,直接返回false
                //core=true: 表示该线程是核心线程,否则该线程作为普通线程,
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))//core=true: 使用线程池的核心线程数来判断,core=false:使用线程池的最大线程数来判断
                    return false;
                //若将当前线程池的状态ctl修改成功(即线程数加1),则跳出循环到 retry 处,否则进入下一循环看总的线程数是否减少(即是否有线程执行完结束了)
                //增加 ctl的值,
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                //获取ctl 的值
                c = ctl.get();  // Re-read ctl
                //若 ctl 的值被修改了,则跳出本次循环
                if (runStateOf(c) != rs)
                    continue retry;
                //  CAS失败,由于workerCount变化;重试内循环
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //将任务线程封装成 worker,创建线程
            w = new Worker(firstTask);
            //获取通过ThreadFactory 构建的线程,
            // 其实也是当前的工作线程,只是装饰一下
            final Thread t = w.thread;
            if (t != null) {
                //获取显式锁对象
                final ReentrantLock mainLock = this.mainLock;
                //加锁
                mainLock.lock();
                try {
                    // 锁定时重新价差
                    //  锁在 ThreadFactory 失败时或 在 lock acquired 之前关闭时退出
                    int rs = runStateOf(ctl.get());//获取ctl 的值

                    if (rs < SHUTDOWN || //线程池状态小于SHUTDOWN,即当前线程池处于运行中状态
                        (rs == SHUTDOWN && firstTask == null)) {//当前线程池状态等于 SHUTDOWN,且 任务线程为null
                        if (t.isAlive()) // precheck that t is startable 预检查 t 是可以启动的,则抛出线程状态异常
                            throw new IllegalThreadStateException();
                        //添加worker,即添加工作线程到 集合workers
                        workers.add(w);
                        //获取所有的工作线程
                        int s = workers.size();
                        //更新 largestPoolSize
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        //设置添加成功
                        workerAdded = true;
                    }
                } finally {
                    //释放锁
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //工作线程添加成功后,启动当前工作线程
                    /**
                     * todo 注意:
                     *    这里真正执行的就是 Worker 的run() 方法
                     */
                    t.start();
                    //设置启动成功
                    workerStarted = true;
                }
            }
        } finally {
            //启动失败,将工作线程从 集合workers 中删除,并将ctl自减
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

     

3、reject(Runnable command)

      reject 表示调用拒绝策略,来处理拒绝的任务;线程池中的拒绝策略请参考前边的内容

      reject 方法定义如下:

/**
     
     * 为指定程序调用的被拒绝的执行处理程序。包保护,由ScheduledThreadPoolExecutor使用。
     */
    final void reject(Runnable command) {
        //拒绝策略
        handler.rejectedExecution(command, this);
    }

4、addWorkerFailed(Worker w)

      addWorkerFailed 用来回滚addWorker 中创建的工作线程

      addWorkerFailed 代码如下:

/**
     * 回滚创建的工作线程。
     */
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                workers.remove(w);
            //减少ctl的值
            decrementWorkerCount();
            //更新线程池状态
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }


private void decrementWorkerCount() {
        //减少ctl的值。这只在线程突然终止时被调用(参见processWorkerExit)。其他减量在getTask中执行。
        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
    }


5、tryTerminate()

      tryTerminate 方法主要功能是,如果(SHUTDOWN和池和队列为空)或(STOP和池为空),

      则转换到终止状态。如果符合终止条件,但workerCount非零,则中断一个空闲的工作器,

      以确保关闭信号传播。这个方法必须在任何可能导致终止的操作之后被调用——减少工作

      人员的数量或在关机期间从队列中删除任务。

      该方法是非私有的,允许从ScheduledThreadPoolExecutor访问。

      tryTerminate 方法代码如下:

final void tryTerminate() {
        //自旋
        for (;;) {
            //获取线程池状态
            int c = ctl.get();
            //若线程池是在运行状态 或 TIDYING 状态 或 SHUTDOWN状态且工作队列不为空,则不能将线程池转换为终止状态,终止往下执行
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //判断释放可以中止的工作器worker,若worker 不为0,则只中断一个空闲的工作器
            if (workerCountOf(c) != 0) { // Eligible to terminate
                //中断一个工作器(即一个工作线程)
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            // 上面的条件不满足,
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        // 钩子函数
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        //唤醒所有的任务线程,在这里启动阻塞任务线程的执行
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }



/**
     * 方法在执行程序终止时调用。默认的实现什么都不做。
     * 注意:正确嵌套多个重写,子类通常应该调用 {@code超级。在这个方法中终止}。
     */
    protected void terminated() { }

6、内部类Worker

     Worker 主要用来维护正在运行中的线程的中断状态,worker可以被看作是一个执行器

     AbstractQueuedSynchronizer,以简化获取和释放围绕每个任务执行的锁。这可以防止那

    些旨在唤醒等待任务的工作线程而不是中断正在运行的任务的中断。我们实现了一个简单

    的不可重入互斥锁,而不是使用ReentrantLock,因为我们不希望工作任务在调用 

    ScheduledExecutorService这样的池控制方法时能够重新获得锁。

    一个工作器表示线程池中一个工作线程,一个工作线程可能会执行多个任务。

    Worker 定义如下:

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * 
         */
        private static final long serialVersionUID = 6138294804551838833L;

        //线程,表示线程池中的工作线程。如果工厂失败,则为空。
        final Thread thread; 
        //thread线程的第一个任务
        Runnable firstTask;
        //线程任务计数器,统计每个线程完成的任务数,即task 个数
        volatile long completedTasks;

        /**
         * 在Worker 构造函数中创建线程
         */
        Worker(Runnable firstTask) {
            //初始化同步状态值
            setState(-1); //  禁止中断,直到runWorker
            this.firstTask = firstTask;
            /**
             * 以当前worker对象构建一个新的线程,用来执行firstTask
             * 在ThreadFactory 中可以对线程池中的线程做些处理,如设置线程名称,可以参考 DefaultThreadFactory 类的实现
             */
            this.thread = getThreadFactory().newThread(this);
        }


        /**   */
        public void run() {
            //将当前worker委托给外部的 runWorker() 方法执行
            //todo 核心方法
            runWorker(this);
        }

      
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        //当前线程显式的获取锁,0:没有持有锁,1:持有锁
        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                //原子的设置当前线程持有锁
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //显式的释放锁
        protected boolean tryRelease(int unused) {
            //设置没有线程持有锁
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        //中断当前正在运行中的线程
        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值