Java 中的线程有六种状态,这些状态定义在 Thread.State 枚举中。以下是这六种状态及其之间的流转关系:
线程的六种状态
- NEW(新建状态):
线程在创建后,但还没有调用 start() 方法时,处于 NEW 状态。
线程对象被实例化,但还未开始执行。
- RUNNABLE(可运行状态):
线程调用了 start() 方法后,进入 RUNNABLE 状态。
线程可能正在执行(CPU 正在执行该线程),也可能是就绪状态,等待操作系统调度执行。注意:在 Java 中,RUNNABLE 既包括了线程在运行的状态,也包括了线程准备好可以运行但暂时未被操作系统调度的状态。
BLOCKED(阻塞状态):
线程处于 BLOCKED 状态时,表示它正在等待获取某个锁,以便执行接下来的操作。
这种状态通常发生在多个线程竞争同一资源(如锁)时。线程在等待获得锁时被阻塞,直到锁可用。
WAITING(等待状态):
线程调用了 Object.wait()。
线程调用了 Thread.join()(没有指定超时)。
线程调用了 LockSupport.park()。
线程进入 WAITING 状态时,表示它正在等待其他线程的某个操作来唤醒它,且没有设定超时限制。
常见的情况是:
TIMED_WAITING(定时等待状态):
线程调用了 Thread.sleep(milliseconds)。
线程调用了 Object.wait(milliseconds)。
线程调用了 Thread.join(milliseconds)。
线程调用了 LockSupport.parkNanos() 或 LockSupport.parkUntil()。
线程进入 TIMED_WAITING 状态时,表示它正在等待某个条件满足,但等待是有超时限制的。
线程会等待一段时间,超时后会自动被唤醒。
常见的情况是:
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 状态的概念重合。
具体原因:
- RUNNABLE 状态包括正在执行和就绪的线程:
在 Java 的线程状态模型中,RUNNABLE 状态既包括了线程已经在 CPU 上执行的状态(实际上正在运行),也包括了线程处于就绪队列中,等待 CPU 分配时间片的状态。
线程一旦被操作系统调度执行,它就进入 RUNNABLE 状态,但这个状态的定义并不区分是否正在执行。操作系统负责将线程从就绪队列中调度到实际的执行状态,并且 Java 并不会对这个过程做细分。
- 线程状态模型的设计:
Java 线程状态模型的设计简化了线程的生命周期管理,没有单独为运行中的线程定义一个状态。RUNNABLE 状态作为一个集合状态,能够涵盖线程既可能在执行也可能在等待 CPU 资源的场景。
在操作系统中,线程的调度是由操作系统内核进行的,Java 并不直接控制线程的执行时间或如何选择线程,而是通过 Java 的线程调度器(JVM)委托给操作系统。所以,线程一旦在运行,实际上是 "正在运行" 或 "就绪等待" 都在 RUNNABLE 状态下进行管理。
JVM 调度与操作系统的区别:
线程的生命周期与操作系统的调度密切相关。在 Java 中,线程进入 RUNNABLE 状态意味着它已经准备好由操作系统调度,但操作系统可能会把它从 CPU 上切换出去,导致线程不再“运行”。
JVM 不强制区分 运行中 和 就绪中,因为从 JVM 的角度看,线程要么处于 RUNNABLE 状态,要么因为某种原因(如阻塞、等待等)不再处于运行状态。