线程
线程是调度CPU资源的最小单位,线程模型分为KLT模型与ULT模型,JVM使用的KLT模
型,Java线程与OS线程保持1:1的映射关系,也就是说有一个java线程也会在操作系统里有
一个对应的线程。Java线程有多种生命状态:
NEW
,
新建
RUNNABLE
,
运行
BLOCKED
,
阻塞
WAITING
,
等待
TIMED_WAITING
,
超时等待
TERMINATED
,终结
协程
协程 (纤程,用户级线程),目的是为了追求最大力度的发挥硬件性能和提升软件的速
度,协程 基本原理是:在某个点挂起当前的任务,并且保存栈信息,去执行另一个任
务;等完成或达到某个条件时,再还原原来的栈信息并继续执行(整个过程线程不需要
上下文切换)。
Java原生不支持协程,在纯java代码里需要使用协程的话需要引入第三方包,如: quasar。
内核线程模型
内核线程(KLT):系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会
引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管
理由内核完成,效率比ULT要慢,比进程操作快。
用户线程模型
用户线程(ULT):用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程
的函数来控制用户线程。不需要用户态/内核态切换,速度快。内核对ULT无感知,线程阻
塞则进程(包括它的所有线程)阻塞。无法利用多核多CPU,只能在同一个CPU核上运行。
线程状态切换图
线程池状态
private final
AtomicInteger
ctl
=
new
AtomicInteger(
ctlOf
(
RUNNING
,
0
));
private static final int
COUNT_BITS
= Integer.
SIZE
3
;
private static final int
CAPACITY
= (
1
<<
COUNT_BITS
)
1
;
ctl
是对线程池的运行状态和线程池中有效线程的数量进行控制的一个字段, 它包含两
部分的信息: 线程池的运行状态 (runState) 和线程池内有效线程的数量 (workerCount),这
里可以看到,使用了Integer类型来保存,高3位保存runState,低29位保存
workerCount。COUNT_BITS 就是29,CAPACITY就是1左移29位减1(
29个1),这个常
量表示workerCount的上限值,大约是5亿。
ctl相关方法
private static int
runStateOf(
int
c) {
return
c & ~
CAPACITY
; }
private static int
workerCountOf(
int
c) {
return
c &
CAPACITY
; }
private static int
ctlOf(
int
rs,
int
wc) {
return
rs | wc; }
runStateOf
:获取运行状态;
workerCountOf
:获取活动线程数;
ctlOf
:获取运行状态和活动线程数的值。
线程池存在5种状态
1
RUNNING
= ‐
1
<<
COUNT_BITS;
//
高
3
位为
111
2
SHUTDOWN
=
0
<<
COUNT_BITS;
//
高
3
位为
000
3
STOP
=
1
<<
COUNT_BITS;
//
高
3
位为
001
4
TIDYING
=
2
<<
COUNT_BITS;
//
高
3
位为
010
5
TERMINATED
=
3
<<
COUNT_BITS;
//
高
3
位为
011
1、RUNNING
(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行
处理。
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处
于RUNNING状态,并且线程池中的任务数为0!
2、 SHUTDOWN
(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
3、STOP
(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中
断正在处理的任务。
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or
SHUTDOWN ) -> STOP。
4、TIDYING
(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING
状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在
ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;
可以通过重载terminated()函数来实现。
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也
为空时,就会由 SHUTDOWN -> TIDYING。 当线程池在STOP状态下,线程池中执行的
任务为空时,就会由STOP -> TIDYING。
5、 TERMINATED
(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -
> TERMINATED。
进入TERMINATED的条件如下:
线程池不是RUNNING状态;
线程池状态不是TIDYING状态或TERMINATED状态;
如果线程池状态是SHUTDOWN并且workerQueue为空;
workerCount为0;
设置TIDYING状态成功。