1、线程的状态
线程有六种状态:分别如下
① NEW(新建)
线程刚被创建,但是并未启动。还没调用start方法
② Runnable(可运行)
线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器
③ Blocked(锁阻塞)
当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态
④ Waiting(无限等待)
一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒
⑤ Timed Waiting(计时等待)
同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait
⑥ Terminated(被终止)
因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡
扩展:
线程的六种状态一般会体现在线程的生命周期中接下来顺便介绍一下线程的生命周期~
二、线程的生命周期
而一个线程的声明周期一般从新建状态(New)开始,到死亡状态(Dead)结束,中间可以存在许多中可能。
如上图所示,一般情况下会有4个分支情况。
1)正常情况
如上图中红色箭头所示,正常状态下线程的声明周期是这样的:NEW -> RUNNABLE -> RUNNING -> DEAD。
分别是正常情况(红色箭头),发生锁阻塞(同步阻塞)的情况(蓝色箭头),发生等待阻塞的情况(黄色箭头),发生其他阻塞的情况(黑色箭头),分别对应上图4个不同颜色的流向。
2)发生锁阻塞(同步阻塞)
如上图中蓝色箭头所示,当线程进入 RUNNING 状态时进入了 synchronized 方法块,这时就会发生锁阻塞,线程进入一个 Lock Pool 锁池中。当其获得锁之后,又进入到可运行状态。当CPU分片轮询到它的时候,它就再次运行,直至 DEAD 状态。
3)发生等待阻塞
如上图中蓝色箭头所示,当线程进入 RUNNING 状态时遇到了 wait() 方法,这时就会发生等待阻塞,它会等待其他线程调用 notify() 方法释放锁之后才可恢复到可运行状态。当CPU分片轮询到它的时候,它就再次运行,直至 DEAD 状态。等待阻塞和锁阻塞其实是同一类型的,都是因为争夺锁而发生的线程等待,唯一的不同是因为它们调用的是不同的方式实现,但底层原理相同。要注意的是执行 wait() 方法的时候,线程一定要获得锁,所以 wait() 方法一般都在 synchronized 方法或代码块中。当其获得锁之后进入等待池(wait pool)并释放锁。收到 notify() 通知之后等待获取锁,获取锁之后才可以运行。
4)发生其他阻塞(如:IO读取等)
tify() 通知之后等待获取锁,获取锁之后才可以运行。
4)发生其他阻塞(如:IO读取等)
当线程需要去读取文件,而此时文件又被其他线程占用,那么就会发生阻塞。这时候线程需要等待其他线程读取完之后才能继续进行,这可以称为 IO 阻塞。当然了还有很多种情况,如网络阻塞等等。