简介
本文介绍Java线程池的原理,包括:线程池的流程、线程池的结构、线程池的任务状态。
执行流程
流程图
在启动时,核心线程池就初始化完毕,等待接收任务。
- 提交任务
- 线程池判断核心线程池(核心线程数)里的线程是否已经满了(全都在执行任务)。
- 如果没满:使用空闲的线程来执行任务。
- 如果满了,则进入下个流程。
- 线程池判断工作队列是否已满。
- 如果没有满,则将新提交的任务存储在这工作队列里。
- 如果工作队列满了,则进入下一个流程。
- 线程池判断线程池的所有线程(最大线程数)是否已经满了(全都在执行任务)。
- 如果不是:则创建一个新的线程来执行任务。
- 如果是:则交给饱和策略来处理这个任务。(饱和策略见:链接)
线程池结构
组成部分
一个线程池包括四个基本部分
- 线程管理池(ThreadPool)
- 用于创建并管理线程池,有创建,销毁,添加新任务;
- 工作线程(PoolWorker)
- 线程池中的线程在没有任务的时候处于等待状态,可以循环的执行任务;
- 任务接口(Task)
- 每个任务必须实现接口,用来提供工作线程调度任务的执行,规定了任务的入口以及执行结束的收尾工作和任务的执行状态等;
- 任务队列
- 用于存放没有处理的任务,提供一种缓存机制。
类的关系
- Executor是一个顶层接口
- 只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型
- 从字面意思可以理解,就是用来执行传进去的任务的。
- ExecutorService接口继承了Executor接口
- 声明了一些方法:submit、invokeAll、invokeAny以及shutDown等
- 抽象类AbstractExecutorService实现了ExecutorService接口
- 实现了ExecutorService中声明的所有方法
- ThreadPoolExecutor继承了类AbstractExecutorService
比较重要的类:
类 | 描述 |
ExecutorService | 真正的线程池接口。 |
ScheduledExecutorService | 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。 |
ThreadPoolExecutor | ExecutorService的默认实现。 |
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。 |
请先
!