一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
简介
线程在任何一个时刻只能处于一种状态,可以使用 getState() 获取线程的状态。
操作系统层面的五种状态
从操作系统层面来看,线程有五种状态:
- 新建
New - 就绪
Ready - 运行
Running - 阻塞
Blocked - 死亡
Dead
Java API 层面的六种状态
从 Java API 层面来看,线程有六种状态:
- 新建
NEW - 可运行
RUNNABLE - 阻塞
BLOCKED - 等待
WAITING - 计时等待
TIMED_WAITING - 终止
TERMINATED
它们在 Thread 类的内部枚举 State 中定义:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
新建
- 创建了线程对象,但是还没有调用
start()方法的线程处于新建状态。 - 只能对处于新建状态的线程调用
start()方法,否则将引发IllegalThreadStateException异常。
可运行
- 可运行状态对应操作系统的两种状态,也就是就绪
Ready状态和运行Running状态。 Java中,处于Runnable状态的线程有可能在等待CPU资源,也有可能正在执行。
阻塞
- 当一个线程进入
synchronized保护的代码时,获取monitor锁失败,它将从可运行状态转变为阻塞状态。
等待
- 调用
Object.wait、Thread.join和LockSupport.park会让一个线程进入等待状态。 - 处于等待状态的线程需要等待另外的线程执行特定操作。
计时等待
- 调用
Thread.sleep(long millis)、Object.wait(long timeout)、Thread.join(long millis)、LockSupport.parkNanos(long nanos)和LockSupport.parkUntil(long deadline)会让一个线程进入计时等待状态。 - 计时等待状态类似等待状态,只不过有一个特定的等待时长,如果等待超时将由系统自动唤醒。
终止
- 线程执行完成的状态
- 进入终止状态有两种可能
run()方法执行完毕,线程正常退出- 出现一个没有捕获的异常,终止了
run()方法,最终导致意外终止
注意
- 被
notify()或者notifyAll()方法唤醒的线程会直接进入阻塞状态,因为唤醒线程的线程如果要调用notify()或者notifyAll(),要求必须首先持有该monitor锁,所以处于等待或者计时等待状态的线程被唤醒时拿不到锁,于是进入阻塞状态。 - 线程的状态是需要按照箭头方向来走的,比如线程从
New状态是不可以直接进入Blocked状态的,它需要先经历Runnable状态。 - 线程生命周期不可逆。一旦进入
Runnable状态就不能回到New状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次New和Terminated状态,只有处于中间状态才可以相互转换。
参考资料
- 《疯狂 Java 讲义:第 5 版》16.3 线程的生命周期
- 黑马 Java 并发编程
- Java 并发编程 78 讲