Java 并发编程 03:线程的状态

130 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

简介

线程在任何一个时刻只能处于一种状态,可以使用 getState() 获取线程的状态。

操作系统层面的五种状态

操作系统层面来看,线程有五种状态:

  • 新建 New
  • 就绪 Ready
  • 运行 Running
  • 阻塞 Blocked
  • 死亡 Dead

202204072135 Java 并发编程 03:线程的状态 00.png

Java API 层面的六种状态

Java API 层面来看,线程有六种状态:

  • 新建 NEW
  • 可运行 RUNNABLE
  • 阻塞 BLOCKED
  • 等待 WAITING
  • 计时等待 TIMED_WAITING
  • 终止 TERMINATED

它们在 Thread 类的内部枚举 State 中定义:

public enum State {
	NEW,
	RUNNABLE,
	BLOCKED,
	WAITING,
	TIMED_WAITING,
	TERMINATED;
}

202204072135 Java 并发编程 03:线程的状态 01.png

新建

  • 创建了线程对象,但是还没有调用 start() 方法的线程处于新建状态。
  • 只能对处于新建状态的线程调用 start() 方法,否则将引发 IllegalThreadStateException 异常。

可运行

  • 可运行状态对应操作系统的两种状态,也就是就绪 Ready 状态和运行 Running 状态。
  • Java 中,处于 Runnable 状态的线程有可能在等待 CPU 资源,也有可能正在执行。

阻塞

  • 当一个线程进入 synchronized 保护的代码时,获取 monitor 锁失败,它将从可运行状态转变为阻塞状态。

等待

  • 调用 Object.waitThread.joinLockSupport.park 会让一个线程进入等待状态。
  • 处于等待状态的线程需要等待另外的线程执行特定操作。

计时等待

  • 调用 Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(long nanos)LockSupport.parkUntil(long deadline) 会让一个线程进入计时等待状态。
  • 计时等待状态类似等待状态,只不过有一个特定的等待时长,如果等待超时将由系统自动唤醒。

终止

  • 线程执行完成的状态
  • 进入终止状态有两种可能
    • run() 方法执行完毕,线程正常退出
    • 出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止

注意

  1. notify() 或者 notifyAll() 方法唤醒的线程会直接进入阻塞状态,因为唤醒线程的线程如果要调用 notify() 或者 notifyAll(),要求必须首先持有该 monitor 锁,所以处于等待或者计时等待状态的线程被唤醒时拿不到锁,于是进入阻塞状态。
  2. 线程的状态是需要按照箭头方向来走的,比如线程从 New 状态是不可以直接进入 Blocked 状态的,它需要先经历 Runnable 状态。
  3. 线程生命周期不可逆。一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次 NewTerminated 状态,只有处于中间状态才可以相互转换。

参考资料

  • 《疯狂 Java 讲义:第 5 版》16.3 线程的生命周期
  • 黑马 Java 并发编程
  • Java 并发编程 78 讲