所有分类
  • 所有分类
  • 未分类

Java-线程池的原理(执行流程/状态转换)

简介

本文介绍Java线程池的原理,包括:线程池的流程、线程池的结构、线程池的任务状态。

执行流程

流程图

在启动时,核心线程池就初始化完毕,等待接收任务。

  1. 提交任务
  2. 线程池判断核心线程池(核心线程数)里的线程是否已经满了(全都在执行任务)。
    1. 如果没满:使用空闲的线程来执行任务。
    2. 如果满了,则进入下个流程。
  3. 线程池判断工作队列是否已满。
    1. 如果没有满,则将新提交的任务存储在这工作队列里。
    2. 如果工作队列满了,则进入下一个流程。
      1. 队列见:Java-阻塞队列(BlockingQueue)的用法(有实例) – 自学精灵
  4. 线程池判断线程池的所有线程(最大线程数)是否已经满了(全都在执行任务)。
    • 如果不是:则创建一个新的线程来执行任务。
    • 如果是:则交给饱和策略来处理这个任务。(饱和策略见:链接

线程池结构

组成部分

一个线程池包括四个基本部分

  1. 线程管理池(ThreadPool)
    1. 用于创建并管理线程池,有创建,销毁,添加新任务;
  2. 工作线程(PoolWorker)
    1. 线程池中的线程在没有任务的时候处于等待状态,可以循环的执行任务;
  3. 任务接口(Task)
    1. 每个任务必须实现接口,用来提供工作线程调度任务的执行,规定了任务的入口以及执行结束的收尾工作和任务的执行状态等;
  4. 任务队列
    1. 用于存放没有处理的任务,提供一种缓存机制。

类的关系

  • Executor是一个顶层接口
    • 只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型
    • 从字面意思可以理解,就是用来执行传进去的任务的。
  • ExecutorService接口继承了Executor接口
    • 声明了一些方法:submit、invokeAll、invokeAny以及shutDown等
  • 抽象类AbstractExecutorService实现了ExecutorService接口
    • 实现了ExecutorService中声明的所有方法
  • ThreadPoolExecutor继承了类AbstractExecutorService

比较重要的类:

描述
ExecutorService真正的线程池接口。
ScheduledExecutorService能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutorExecutorService的默认实现。
ScheduledThreadPoolExecutor继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

线程池状态

状态图

线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。

状态说明状态切换
RUNNING线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。创建时会调用此语句: private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!
SHUTDOWN线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
STOP线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
TIDYING当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。 当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
TERMINATED线程池彻底终止,就变成TERMINATED状态。线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
0

评论9

请先

  1. 我看好多资料说线程池的核心线程是懒加载的,只有第一个任务进来才创建核心线程
    daijunren 2024-05-19 0
    • 这个与具体的线程池实现有关系,有的不是懒加载,有的是懒加载。常用的固定大小线程池不是懒加载,CachedThreadPool和ScheduledThreadPool是懒加载。
      自学精灵 2024-05-20 0
  2. 我真的,可不可以提前把答案先给出来呀,我脑子笨,悟不出来呀,兄弟
    锈湖 2024-03-04 3
    • 这种类似的问题都是比较浅显的,实在不好再写了
      自学精灵 2024-03-04 0
    • 在Java中,使用java.util.concurrent.ThreadPoolExecutor来创建线程池时,触发最大线程条件的情形遵循以下规则: 工作队列已满:当提交到线程池的任务数量超过核心线程数,并且线程池配置的任务队列(如ArrayBlockingQueue、LinkedBlockingQueue等)已达到其容量上限,无法再接受新的任务等待执行。 活动线程未达最大值:在工作队列满的情况下,如果当前活动线程的数量少于线程池设定的最大线程数(通过maximumPoolSize参数配置),线程池会创建新的线程来处理这些任务,直到达到最大线程数。 拒绝策略应用之前:一旦活动线程数达到最大线程数,并且没有空间在队列中放置新任务,任何进一步的提交将依据线程池的拒绝策略来处理。默认的拒绝策略是AbortPolicy,它会抛出一个RejectedExecutionException异常。用户也可以通过重写RejectedExecutionHandler来自定义拒绝策略,比如静默抛弃任务(DiscardPolicy)、由调用线程自己执行任务(CallerRunsPolicy)等。
      ゞ╃尐沐則颩...o 2024-06-05 0
  3. 这里第一步有点疑问,核心线程池应该是java程序启动就创建好的吧?应该永远不关闭,也不需要新建的,新来的任务发现核心线程池有空位直接执行就好了,不需要创建核心线程池吧?
    goldencowcow 2024-03-01 0
    • 是的,一开始就创建好的。已修复
      自学精灵 2024-03-01 0
      • 为什么要创建核心线程池哟
        锈湖 2024-03-04 0
        • 线程,肯定要创建才能有呀
          自学精灵 2024-03-04 0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录