热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

上一篇主要从代码角度介绍了线程池关闭相关的方法,包括各个方法之间的逻辑关系,调用关系和产生的效果。这一篇更多从逻辑角度上来说一下线程池在shutdown之后,原来正常的处理流程有哪些变

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

这一篇更多从逻辑角度上来说一下线程池在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)  
 

有以下几种情况:

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退出的相关操作。



推荐阅读
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • 在Java中,我会做这样的事情:classPerson{privateRecordrecord;publicStringname(){record().get(name);}p ... [详细]
  • FineReport平台数据分析图表显示部分系列接口的应用场景和实现思路
    本文介绍了FineReport平台数据分析图表显示部分系列接口的应用场景和实现思路。当图表系列较多时,用户希望可以自己设置哪些系列显示,哪些系列不显示。通过调用FR.Chart.WebUtils.getChart("chartID").getChartWithIndex(chartIndex).setSeriesVisible()接口,可以获取需要显示的系列图表对象,并在表单中显示这些系列。本文以决策报表为例,详细介绍了实现方法,并给出了示例。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 一、什么是闭包?有什么作用什么是闭包闭包是定义在一个函数内部的函数,它可以访问父级函数的内部变量。当一个闭包被创建时,会关联一个作用域—— ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文主要介绍了gym102222KVertex Covers(高维前缀和,meet in the middle)相关的知识,包括题意、思路和解题代码。题目给定一张n点m边的图,点带点权,定义点覆盖的权值为点权之积,要求所有点覆盖的权值之和膜qn小于等于36。文章详细介绍了解题思路,通过将图分成两个点数接近的点集L和R,并分别枚举子集S和T,判断S和T能否覆盖所有内部的边。文章还提到了使用位运算加速判断覆盖和推导T'的方法。最后给出了解题的代码。 ... [详细]
  • Python中的PyInputPlus模块原文:https ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
author-avatar
爱文小宝的贇
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有