ThreadPoolExecutor(六)——线程池关闭之后

 上一篇主要从代码角度介绍了线程池关闭相关的方法,包括各个方法之间的逻辑关系,调用关系和产生的效果。

这一篇更多从逻辑角度上来说一下线程池在shutdown之后,原来正常的处理流程有哪些变化,既是总结也是扩展。

shutdown操作之后,首先最重要的一点变化就是线程池状态变成了SHUTDOWN。该状态是开始关闭线程池之后,从RUNNING改变状态经过的第一个状态(还有一种情况是直接进STOP,调用shutdownNow的时候),有个图画的挺好,见博客Java 7之多线程线程池 - 线程池原理(2)

从入口开始看,在这个状态变化之后,每个方法的处理流程和之前比发生了什么变化?

1.execute

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

有以下几种情况:

1.如果现在状态不是RUNNING,说明要么正在SHUTDOWN要么已经SHUTDOWN完毕了,这时isRunning方法是false,会走到最后一个else if中,通过addWorker的状态来执行相应操作。addWorker下一个段落会说。

2.如果现在是RUNNING操作,而且入队列成功了,然后这里需要一个double check,重新检测线程池的状态,如果不是RUNNING,而且remove成功,直接reject任务。如果remove方法失败,什么都不做(因为有其他的方法正在remove任务,比如shoutDownNow的drainQueue,purge,runWorker结束时的processWorkerExit)。

3.如果现在是RUNNING操作,如果offer失败了,说明队列满了,也执行最后一个if else,调用addWorker,这时也可能开启了SHUTDOWN操作。

2.addWorker

// Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

先看这个会返回false的判断,

1.STOP,TIDYING和TERMINATED这三种状态都会直接返回false。

2.如果是SHUTDOWN,而且firstTask不是null,也返回false。

3.如果是SHUTDOWN,firstTask是null,而且任务队列是空,返回false。

现在要看的是SHUTDOWN状态,fistTask是null,任务队列不是空的情况。

addWorker(null, X)这种传参方式,除了初始化线程数的时候,只有processWorkerExit,execute的recheck发现wc个数为0,这两种情况。

关于addWorker传null的含义还有些迷惑,上一篇中也特意有一个段落说这个问题,以后再研究下看看有没有新的理解和发现。

3.getTask

/**
     * Performs blocking or timed wait for a task, depending on
     * current configuration settings, or returns null if this worker
     * must exit because of any of:
     * 1. There are more than maximumPoolSize workers (due to
     *    a call to setMaximumPoolSize).
     * 2. The pool is stopped.
     * 3. The pool is shutdown and the queue is empty.
     * 4. This worker timed out waiting for a task, and timed-out
     *    workers are subject to termination (that is,
     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
     *    both before and after the timed wait.
     *
     * @return task, or null if the worker must exit, in which case
     *         workerCount is decremented
     */
    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            boolean timed;      // Are workers subject to culling?

            for (;;) {
                int wc = workerCountOf(c);
                timed = allowCoreThreadTimeOut || wc > corePoolSize;

                if (wc <= maximumPoolSize && ! (timedOut && timed))
                    break;
                if (compareAndDecrementWorkerCount(c))
                    return null;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

先看注释:

在取任务的时候有两种策略,一直阻塞或带超时的等待,取决于线程池的参数设置。返回null如果该Worker由于以下几种情况退出:

1.wc的数量超过了maximumPoolSize了(通常由于)调用了setMaximumPoolSize方法临时减小了maximumPoolSize值,这时返回null来干掉Worker。

2.线程池处于STOP状态。

3.线程池处于SHUTDOWN状态,而且任务队列是空的。

4.Worker在等待任务的时候超时了,而且超时的Worker需要被terminated,条件是allowCoreThreadTimeOut || workerCount > corePoolSize,即当该线程池允许核心线程timeout(无论是max还是core的Worker都会退出)或者当前wc个数已经超过了核心线程数的时候(退出的max线程的Worker),Worker可以退出线程池。
 

4.runWorker

runWorker中调用了getTask方法,所以其相应执行结果和getTask的返回有关。比如上一个段落中说的那几种情况,线程池在SHUTDOWN状态且任务队列为空,会返回null。线程池在STOP状态也会返回null(不检查队列是否为空,因为STOP状态是shutdownNow引起的,所有task都已经被drainQueue方法移除了)。

而返回null意味着runWorker中的循环会结束,然后调用processWorkerExit方法去做一些Worker退出的相关操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值