文章插图
ThreadPoolExecutor优雅停止线程池的优雅停止一般要能做到以下几点:
- 线程池在中止后不能再受理新的任务
- 线程池中止的过程中,已经提交的现存任务不能丢失(等待剩余任务执行完再关闭或者能够把剩余的任务吐出来还给用户)
- 线程池最终关闭前,确保创建的所有工作线程都已退出 , 不会出现资源的泄露
ThreadPoolExecutor的其它功能除了正常的工作流程以及优雅停止的功能外 , ThreadPoolExecutor还提供了一些比较好用的功能
- 提供了很多protected修饰的钩子函数,便于用户继承并实现自己的线程池时进行一定的拓展
- 在运行时统计了总共执行的任务数等关键指标,并提供了对应的api便于用户在运行时观察运行状态
- 允许在线程池运行过程中动态修改关键的配置参数(比如corePoolSize等) , 并实时的生效 。
前面提到ThreadPoolExecutor的核心逻辑主要分为两部分,一是正常运行时处理提交的任务的逻辑,二是实现优雅停止的逻辑 。因此我们实现的线程池MyThreadPoolExecutor(以My开头用于区分)也会分为两个版本,v1版本只实现前一部分即正常运行时执行任务的逻辑,将有关线程池优雅停止的逻辑全部去除 。相比直接啃jdk最终实现的源码,v1版本的实现会更简单更易理解 , 让正常执行任务时的逻辑更加清晰而不会耦合太多关于优雅停止的逻辑 。
线程池关键成员变量介绍ThreadPoolExecutor中有许多的成员变量,大致可以分为三类 。
可由用户自定义的、用于控制线程池运行的配置参数
- volatile int corePoolSize(最大核心线程数量)
- volatile int maximumPoolSize(最大线程数量)
- volatile long keepAliveTime(idle线程保活时间)
- final BlockingQueue workQueue(工作队列(阻塞队列))
- volatile ThreadFactory threadFactory(工作线程工厂)
- volatile RejectedExecutionHandler handler(拒绝异常处理器)
- volatile boolean allowCoreThreadTimeOut(是否允许核心线程在idle超时后退出)
仅供线程池内部工作时使用的属性
- ReentrantLock mainLock(用于控制各种临界区逻辑的并发)
- HashSet workers(当前活跃工作线程Worker的集合,工作线程的工作原理会在下文介绍)
- AtomicInteger ctl(线程池控制状态 , control的简写)
ctl这样聚合的设计比起拆分成两个独立的字段有什么好处?在ThreadPoolExecutor中关于优雅停止的逻辑中有很多地方是需要同时判断当前工作线程数量与线程池状态后,再对线程池状态工作线程数量进行更新的(具体逻辑在下一篇v2版本的博客中展开) 。且为了执行效率,不使用互斥锁而是通过cas重试的方法来解决并发更新的问题 。而对一个AtomicInteger属性做cas重试的更新,要比同时控制两个属性进行cas的更新要简单很多,执行效率也高很多 。
推荐阅读
- 我的Vue之旅 10 Gin重写后端、实现页面详情页 Mysql + Golang + Gin
- zk系列三:zookeeper实战之分布式锁实现
- 【深入浅出 Yarn 架构与实现】2-2 Yarn 基础库 - 底层通信库 RPC
- OPPO手机怎么才能设置到自己心仪的彩铃
- 手机动态彩铃是怎么设置的(自己手机的彩铃能设置吗)
- 第2-1-5章 docker安装MinIO实现文件存储服务-springboot整合minio-minio全网最全的资料
- 【深入浅出 Yarn 架构与实现】2-1 Yarn 基础库概述
- Golang 实现时间戳和时间的转化
- 二叉搜索树 - C++ 实现
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境