• Java 线程池及线程池状态


    Java 中的线程池
    • 什么是线程池
      • 线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制,它是将多个线程预先存储在一个池子内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从池子内取出相应的线程执行对应的任务即可

    • 线程池的创建方法总共有 7 种,但总体来说可分为 2 类:
      • 一类是通过 ThreadPoolExecutor 创建的线程池
      • 另一个类是通过 Executors 创建的线程池 ( [Java开发手册] 规范不允许使用)

    • 线程池的创建方式总共包含以下 7 种(其中 6 种是通过 Executors 创建的,1 种是通过 ThreadPoolExecutor 创建的)
      • Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待
      • Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程
      • Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序
      • Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池
      • Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池
      • Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定,,JDK 1.8 添加
      • ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置,后面会详细讲

    • 单线程池的意义从以上代码可以看出 newSingleThreadExecutor 和 newSingleThreadScheduledExecutor 创建的都是单线程池,那么单线程池的意义是什么
      • 虽然是单线程池,但提供了工作队列,生命周期管理,工作线程维护等功能

    • ThreadPoolExecutor 参数介绍
      • public ThreadPoolExecutor(int corePoolSize,
                     int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue workQueue,
                    ThreadFactory threadFactory,
                    RejectedExecutionHandler handler) {
        // 省略…
        }

      • corePoolSize:核心线程数,线程池中始终存活的线程数

      • maximumPoolSize:最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数

      • keepAliveTime:最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程

      • unit: 单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间 ,参数 keepAliveTime 的时间单位有以下 7 种可选:

        • TimeUnit.DAYS:天
        • TimeUnit.HOURS:小时
        • TimeUnit.MINUTES:分
        • TimeUnit.SECONDS:秒
        • TimeUnit.MILLISECONDS:毫秒
        • TimeUnit.MICROSECONDS:微妙
        • TimeUnit.NANOSECONDS:纳秒
      • workQueue:一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全,它包含以下 7 种类型:

        • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列
        • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列
        • SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们
        • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列
        • DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素
        • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列,与 SynchronousQueue 类似,还含有非阻塞方法
        • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列
          较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略与 BlockingQueue 有关
      • threadFactory:线程工厂,主要用来创建线程,默认为正常优先级、非守护线程

      • handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何拒绝,系统提供了 4 种可选:

        • AbortPolicy:拒绝并抛出异常
        • CallerRunsPolicy:使用当前调用的线程来执行此任务
        • DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务
        • DiscardPolicy:忽略并抛弃当前任务
          默认策略为 AbortPolicy

    • ThreadPoolExecutor 关键节点的执行流程如下:


    Java 中线程池状态
    • 线程池总共存在 5 种状态,定义在 ThreadPoolExecutor 类中,代码如下
    public class ThreadPoolExecutor extends AbstractExecutorService {
        private static final int RUNNING    = -1 << COUNT_BITS;
        private static final int SHUTDOWN   =  0 << COUNT_BITS;
        private static final int STOP       =  1 << COUNT_BITS;
        private static final int TIDYING    =  2 << COUNT_BITS;
        private static final int TERMINATED =  3 << COUNT_BITS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 线程池的5种状态具体如下
      • RUNNING:线程池创建之后的初始状态,这种状态下可以执行任务
      • SHUTDOWN:该状态下线程池不再接受新任务,但是会将工作队列中的任务执行完毕
      • STOP:该状态下线程池不再接受新任务,也不会处理工作队列中的剩余任务,并且将会中断所有工作线程
      • TIDYING:该状态下所有任务都已终止或者处理完成,将会执行 terminated() 钩子方法
      • TERMINATED:执行完 terminated() 钩子方法之后的状态。terminated 钩子方法在 Executor 终止时调用,默认实现不执行任何操作

    • 线程池的状态转换规则为:
      • 线程池创建之后状态为 RUNNING
      • 执行线程池的 shutdown() 实例方法,会使线程池状态从 RUNNING 转变为 SHUTDOWN
      • 执行线程池的 shutdownNow() 实例方法,会使线程池状态从 RUNNING 转变为 STOP
      • 当线程池处于 SHUTDOWN 状态时,执行其 shutdownNow() 方法会将其状态转变为 STOP
      • 等待线程池的所有工作线程停止,工作队列清空之后,线程池状态会从 STOP 转变为 TIDYING
      • 执行完 terminated() 钩子方法之后,线程池状态从 TIDYING 转变为 TERMINATED
  • 相关阅读:
    Flink
    最新版ESP32 IDF环境搭建教程:基于CLION同时安装多个版本的IDF
    网络编程 - UDP协议
    C++学习——C++运算符重载(含义、格式、示例、遵循的规则)
    DDD 实战 (2):看看代码结构长啥样(值得收藏)
    springcloud分布式架构网上商城(java项目源码+文档)
    【电源专题】线性稳压器基础(线性稳压器是哪里线性了?)
    【Swift 60秒】08 - Simple types:Summary
    October 2019 Twice SQL Injection
    防止忘了,记录一下
  • 原文地址:https://blog.csdn.net/qq_41956014/article/details/127690490