自己动手实现线程池 jdk线程池ThreadPoolExecutor工作原理解析(一)( 二 )

  • 尝试将当前任务放入工作队列workQueue(阻塞队列BlockingQueue),工作队列中的任务会被线程池中的活跃线程按入队顺序逐个消费 。如果入队成功,则说明当前工作队列未满,入队的任务将会被线程池中的某个活跃线程所消费并执行 。如果入队失败,则说明当前工作队列已饱和,线程池消费任务的速度可能太慢了,可能需要创建更多新线程来加速消费,进行下一步判断 。
  • 判断当前活跃的线程数是否小于指定的最大线程数maximumPoolSize 。如果为真,则说明当前线程池所承载的线程数还未达到参数指定的上限,还有余量来创建新的线程加速消费,创建一个新线程来执行该任务 。如果为假,则说明当前线程池所承载的线程数达到了上限,但处理任务的速度依然不够快,需要触发拒绝策略 。
    自己动手实现线程池 jdk线程池ThreadPoolExecutor工作原理解析(一)

    文章插图
  • ThreadPoolExecutor优雅停止线程池的优雅停止一般要能做到以下几点:
    1. 线程池在中止后不能再受理新的任务
    2. 线程池中止的过程中,已经提交的现存任务不能丢失(等待剩余任务执行完再关闭或者能够把剩余的任务吐出来还给用户)
    3. 线程池最终关闭前,确保创建的所有工作线程都已退出,不会出现资源的泄露
    线程池自启动后便会有大量的工作线程在内部持续不断并发的执行提交的各种任务,而要想做到优雅停止并不是一件容易的事情 。因此ThreadPoolExecutor中最复杂、细节最多的部分并不在于上文中的正常工作流程,而在于分散在各个地方但又紧密协作的,控制优雅停止的逻辑 。
    ThreadPoolExecutor的其它功能除了正常的工作流程以及优雅停止的功能外,ThreadPoolExecutor还提供了一些比较好用的功能
    1. 提供了很多protected修饰的钩子函数,便于用户继承并实现自己的线程池时进行一定的拓展
    2. 在运行时统计了总共执行的任务数等关键指标,并提供了对应的api便于用户在运行时观察运行状态
    3. 允许在线程池运行过程中动态修改关键的配置参数(比如corePoolSize等),并实时的生效 。
    jdk线程池ThreadPoolExecutor源码解析(自己动手实现线程池v1版本)如费曼所说:What I can not create I do not understand(我不能理解我创造不了的东西) 。通过模仿jdk的ThreadPoolExecutor实现,从零开始实现一个线程池,可以迫使自己去仔细的捋清楚jdk线程池中设计的各种细节,加深理解而达到更好的学习效果 。
    前面提到ThreadPoolExecutor的核心逻辑主要分为两部分,一是正常运行时处理提交的任务的逻辑,二是实现优雅停止的逻辑 。因此我们实现的线程池MyThreadPoolExecutor(以My开头用于区分)也会分为两个版本,v1版本只实现前一部分即正常运行时执行任务的逻辑,将有关线程池优雅停止的逻辑全部去除 。相比直接啃jdk最终实现的源码,v1版本的实现会更简单更易理解,让正常执行任务时的逻辑更加清晰而不会耦合太多关于优雅停止的逻辑 。
    线程池关键成员变量介绍ThreadPoolExecutor中有许多的成员变量,大致可以分为三类 。
    可由用户自定义的、用于控制线程池运行的配置参数
    1. volatile int corePoolSize(最大核心线程数量)
    2. volatile int maximumPoolSize(最大线程数量)
    3. volatile long keepAliveTime(idle线程保活时间)
    4. final BlockingQueue workQueue(工作队列(阻塞队列))
    5. volatile ThreadFactory threadFactory(工作线程工厂)
    6. volatile RejectedExecutionHandler handler(拒绝异常处理器)
    7. volatile boolean allowCoreThreadTimeOut(是否允许核心线程在idle超时后退出)
    其中前6个配置参数都可以在ThreadPoolExecutor的构造函数中指定,而allowCoreThreadTimeOut则可以通过暴露的public方法allowCoreThreadTimeOut来动态的设置 。其中大部分属性都是volatile修饰的,目的是让运行过程中可以用过提供的public方法动态修改这些值后,线程池中的工作线程或提交任务的用户线程能及时的感知到变化(线程间的可见性),并进行响应(比如令核心线程自动的idle退出)这些配置属性具体如何控制线程池行为的原理都会在下面的源码解析中展开介绍 。理解这些参数的工作原理后才能在实际的业务中使用线程池时为其设置合适的值 。

    经验总结扩展阅读