线程有几种状态,状态之间的流转是怎样的?

开发 前端
JVM 不强制区分 运行中 和 就绪中,因为从 JVM 的角度看,线程要么处于 RUNNABLE 状态,要么因为某种原因(如阻塞、等待等)不再处于运行状态。​

Java 中的线程有六种状态,这些状态定义在 Thread.State 枚举中。以下是这六种状态及其之间的流转关系:

线程的六种状态

  1. NEW(新建状态):

线程在创建后,但还没有调用 start() 方法时,处于 NEW 状态。

线程对象被实例化,但还未开始执行。

  1. RUNNABLE(可运行状态):

线程调用了 start() 方法后,进入 RUNNABLE 状态。

线程可能正在执行(CPU 正在执行该线程),也可能是就绪状态,等待操作系统调度执行。注意:在 Java 中,RUNNABLE 既包括了线程在运行的状态,也包括了线程准备好可以运行但暂时未被操作系统调度的状态。

  1. BLOCKED(阻塞状态):

线程处于 BLOCKED 状态时,表示它正在等待获取某个锁,以便执行接下来的操作。

这种状态通常发生在多个线程竞争同一资源(如锁)时。线程在等待获得锁时被阻塞,直到锁可用。

  1. WAITING(等待状态):

线程调用了 Object.wait()。

线程调用了 Thread.join()(没有指定超时)。

线程调用了 LockSupport.park()。

线程进入 WAITING 状态时,表示它正在等待其他线程的某个操作来唤醒它,且没有设定超时限制。

常见的情况是:

  1. TIMED_WAITING(定时等待状态):

线程调用了 Thread.sleep(milliseconds)。

线程调用了 Object.wait(milliseconds)。

线程调用了 Thread.join(milliseconds)。

线程调用了 LockSupport.parkNanos() 或 LockSupport.parkUntil()。

线程进入 TIMED_WAITING 状态时,表示它正在等待某个条件满足,但等待是有超时限制的。

线程会等待一段时间,超时后会自动被唤醒。

常见的情况是:

  1. TERMINATED(终止状态):

线程在执行完毕后,进入 TERMINATED 状态。

线程的生命周期结束,线程对象不能再被启动。

线程因为正常完成任务,或者由于异常等原因结束时都会进入这个状态。

状态之间的流转

  • NEW → RUNNABLE

调用 Thread.start() 方法后,线程从 NEW 状态变为 RUNNABLE 状态。

  • RUNNABLE → BLOCKED
  • 线程试图获取已被其他线程持有的监视器锁时,会从 RUNNABLE 状态变为 BLOCKED 状态。

  • BLOCKED → RUNNABLE

  • 当线程获取到所需的监视器锁时,会从 BLOCKED 状态变为 RUNNABLE 状态。

  • RUNNABLE → WAITING

  • 线程调用 Object.wait(), Thread.join(), LockSupport.park() 等方法后,会从 RUNNABLE 状态变为 WAITING 状态。

  • RUNNABLE → TIMED_WAITING

  • 线程调用 Thread.sleep(long millis), Object.wait(long timeout), Thread.join(long millis), LockSupport.parkNanos(long nanos), LockSupport.parkUntil(long deadline) 等方法后,会从 RUNNABLE 状态变为 TIMED_WAITING 状态。

  • WAITING → RUNNABLE

  • 当等待条件满足时,例如 Object.notify(), Object.notifyAll(), Thread.interrupt() 等方法被调用后,线程会从 WAITING 状态变为 RUNNABLE 状态。

  • TIMED_WAITING → RUNNABLE

  • 当等待时间到期或等待条件满足时,线程会从 TIMED_WAITING 状态变为 RUNNABLE 状态。

  • RUNNABLE → TERMINATED

  • 当线程的 run() 方法正常结束或抛出未捕获的异常时,线程会从 RUNNABLE 状态变为 TERMINATED 状态。

图解

+--------+      start()     +-----------+
  |  NEW   |  ------------>  | RUNNABLE  |
  +--------+                 +-----------+
                               |       |
                           +---+       +---+
                           |                       |
                           v                       v
                    +-----------+          +---------------+
                    |  BLOCKED  |          |  WAITING      |
                    +-----------+          +---------------+
                               |                       |
                           +---+       +---+
                           |           |
                           v           v
                    +-----------------+
                    | TIMED_WAITING   |
                    +-----------------+
                               |
                           +---+
                           |
                           v
                    +-----------+
                    | TERMINATED|
                    +-----------+

总结:

  • NEW:线程尚未启动。
  • RUNNABLE:线程正在等待 CPU 调度执行,可能正在运行,也可能等待 CPU 资源。
  • BLOCKED:线程正在等待获取锁。
  • WAITING:线程正在等待其他线程的通知(没有超时)。
  • TIMED_WAITING:线程正在等待某个条件满足,并且设置了超时。
  • TERMINATED:线程已经执行完毕并结束。

WAITING 和 TIMED_WAITING 的区别?

  • WAITING 是无条件的等待,线程会一直等待直到被其他线程唤醒。
  • TIMED_WAITING 是带有超时的等待,线程会等待一段时间,超时后自动唤醒。

这两种状态的关键区别是 是否有超时限制,WAITING 没有时间限制,而 TIMED_WAITING 是有超时的。 

为什么线程没有RUNNING状态?

因为它与 RUNNABLE 状态的概念重合。

具体原因:

  1. RUNNABLE 状态包括正在执行和就绪的线程:

在 Java 的线程状态模型中,RUNNABLE 状态既包括了线程已经在 CPU 上执行的状态(实际上正在运行),也包括了线程处于就绪队列中,等待 CPU 分配时间片的状态。

线程一旦被操作系统调度执行,它就进入 RUNNABLE 状态,但这个状态的定义并不区分是否正在执行。操作系统负责将线程从就绪队列中调度到实际的执行状态,并且 Java 并不会对这个过程做细分。

  1. 线程状态模型的设计:

Java 线程状态模型的设计简化了线程的生命周期管理,没有单独为运行中的线程定义一个状态。RUNNABLE 状态作为一个集合状态,能够涵盖线程既可能在执行也可能在等待 CPU 资源的场景。

在操作系统中,线程的调度是由操作系统内核进行的,Java 并不直接控制线程的执行时间或如何选择线程,而是通过 Java 的线程调度器(JVM)委托给操作系统。所以,线程一旦在运行,实际上是 "正在运行" 或 "就绪等待" 都在 RUNNABLE 状态下进行管理。

  1. JVM 调度与操作系统的区别:

线程的生命周期与操作系统的调度密切相关。在 Java 中,线程进入 RUNNABLE 状态意味着它已经准备好由操作系统调度,但操作系统可能会把它从 CPU 上切换出去,导致线程不再“运行”。

JVM 不强制区分 运行中 和 就绪中,因为从 JVM 的角度看,线程要么处于 RUNNABLE 状态,要么因为某种原因(如阻塞、等待等)不再处于运行状态。

责任编辑:武晓燕 来源: 架构殿堂
相关推荐

2023-11-29 16:29:09

线程java

2022-03-23 08:51:21

线程池Java面试题

2024-04-16 09:21:59

Spring流转状态数据状态处理

2022-08-29 16:03:33

状态流转Java

2024-04-30 11:14:19

KubernetesReplicaSet数量

2022-10-12 14:23:30

Java线程

2023-06-28 07:45:51

Java线程状态

2023-12-01 14:57:22

TCP连接

2024-11-18 16:28:20

2013-12-09 09:56:30

NAT64IPv6stateful

2021-12-26 18:22:30

Java线程多线程

2021-01-31 23:58:04

MySQL状态表数据源

2023-05-08 23:20:49

WebYARN管理

2024-09-27 11:29:32

2022-04-18 07:36:37

TimeUnit线程休眠

2022-06-01 12:00:54

HTTP状态码服务端

2024-05-30 11:53:51

2020-09-10 18:54:50

边缘计算与云计算

2016-01-12 10:27:38

SDN东西流量数据中心

2018-04-18 08:54:28

RDD内存Spark
点赞
收藏

51CTO技术栈公众号