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

分类: 皇冠365体育下载 发布时间: 2026-06-11 16:52:01 作者: admin 阅读: 9574
线程有几种状态,状态之间是怎样流转的?

面试考察点

基础掌握度:面试官不仅仅是想知道有几种状态,更是想考察你是否能准确说出 Java 层面(Thread.State)的 6 种状态,而不是和操作系统的 5 种状态混为一谈。

状态流转理解:能否完整描述每种状态之间的转换条件,特别是 BLOCKED、WAITING、TIMED_WAITING 这三种 "停顿" 状态的区别和触发场景,这是面试的重点。

实践关联:能否结合 synchronized、Lock、sleep()、wait() 等实际 API 来解释状态流转,而不是干巴巴背概念。

核心答案

Java 线程在 Thread.State 枚举中定义了 6 种状态:

状态

含义

是否占用 CPU

NEW

新建,还没调用 start()

RUNNABLE

可运行(包括就绪和运行中)

可能

BLOCKED

阻塞,等待获取锁

WAITING

等待,无限期等待被唤醒

TIMED_WAITING

超时等待,有期限的等待

TERMINATED

终止,线程执行完毕

一句话总结:6 种状态,核心流转路径是 NEW → RUNNABLE →(BLOCKED/WAITING/TIMED_WAITING)→ RUNNABLE → TERMINATED。

深度解析

一、完整状态流转图

图片来源:https://mp.weixin.qq.com/s/0UTyrJpRKaKhkhHcQtXAiA

上图展示了 Java 线程 6 种状态之间的完整流转关系。下面逐条解释每条转换路径:

NEW → RUNNABLE:调用 start() 方法,线程从新建状态进入可运行状态,交给操作系统调度

RUNNABLE → BLOCKED:线程尝试进入 synchronized 代码块/方法,但锁被其他线程持有,进入阻塞状态

RUNNABLE → WAITING:线程调用 Object.wait()、Thread.join()、LockSupport.park() 等方法,主动进入无限期等待

RUNNABLE → TIMED_WAITING:线程调用 Thread.sleep(n)、Object.wait(n)、Thread.join(n) 等带超时的方法

BLOCKED → RUNNABLE:锁释放后,该线程竞争成功获取到锁

WAITING → RUNNABLE:被 notify()/notifyAll() 唤醒,或 LockSupport.unpark() 唤醒,或等待的线程执行完毕(join() 场景)

TIMED_WAITING → RUNNABLE:超时时间到自动唤醒,或在超时前被显式唤醒

WAITING/TIMED_WAITING → BLOCKED:被 notify() 唤醒后需要重新获取锁,如果锁被其他线程持有则进入 BLOCKED

RUNNABLE → TERMINATED:run() 方法执行完毕,或抛出未捕获的异常

二、6 种状态逐一详解

1. NEW(新建)

线程对象已创建,但还没调用 start() 方法。此时线程还没分配系统资源。

Thread t = new Thread(() -> {}); // 此时状态:NEW

// t.start(); // 调用 start() 后才变为 RUNNABLE

2. RUNNABLE(可运行)

注意,Java 层面的 RUNNABLE 包含了操作系统层面的 就绪(Ready) 和 运行中(Running) 两个状态。Java 不区分这两个,统一算 RUNNABLE。

就绪:线程已经准备好,等 CPU 分配时间片

运行中:CPU 正在执行该线程

Thread t = new Thread(() -> {

// 这里面执行时,状态就是 RUNNABLE

// 即使调用了 IO 操作,Java 层面状态仍然是 RUNNABLE(这是 Java 的设计选择)

});

t.start(); // NEW → RUNNABLE

3. BLOCKED(阻塞)

线程在等待获取一把 内置锁(synchronized)。当锁被其他线程持有时,尝试进入 synchronized 代码块/方法的线程就会变成 BLOCKED。

synchronized (lock) { // 如果 lock 被其他线程持有

// 线程状态:BLOCKED // 等待获取锁

// 获取到锁后 → RUNNABLE

}

注意:BLOCKED 只针对 synchronized,使用 ReentrantLock.lock() 时线程进入的是 WAITING(因为底层调用了 LockSupport.park()),不是 BLOCKED。

4. WAITING(无限期等待)

线程进入等待状态,需要其他线程显式唤醒。以下操作会让线程进入 WAITING:

方法

唤醒条件

Object.wait()

需要 notify()/notifyAll()

Thread.join()

等待目标线程执行完毕

LockSupport.park()

需要 LockSupport.unpark()

// 示例:wait/notify

synchronized (lock) {

lock.wait(); // RUNNABLE → WAITING

// 等其他线程调用 lock.notify()

// 被唤醒后 → BLOCKED(重新抢锁)

// 抢到锁后 → RUNNABLE

}

5. TIMED_WAITING(超时等待)

和 WAITING 类似,区别是 有超时时间,时间到了自动唤醒。以下操作会让线程进入 TIMED_WAITING:

方法

说明

Thread.sleep(long)

休眠指定时间

Object.wait(long)

超时等待

Thread.join(long)

超时等待目标线程

LockSupport.parkNanos()

超时阻塞

LockSupport.parkUntil()

阻塞到指定时间点

Thread.sleep(1000); // RUNNABLE → TIMED_WAITING

// 1 秒后自动 → RUNNABLE

6. TERMINATED(终止)

线程执行完毕或因异常退出,不可再启动。

Thread t = new Thread(() -> {});

t.start();

t.join(); // 等待线程执行完

// 此时状态:TERMINATED

三、三种 "停顿" 状态的区别(面试重点)

BLOCKED、WAITING、TIMED_WAITING 都表示线程 "没在跑",但本质不同:

对比维度

BLOCKED

WAITING

TIMED_WAITING

触发原因

等待 synchronized 锁

wait()/join()/park()

sleep()/wait(n)/parkNanos()

等待时长

不确定(等锁释放)

不确定(等别人唤醒)

确定的超时时间

唤醒方式

锁释放后自动竞争

需要显式 notify()/unpark()

超时自动唤醒,或被显式唤醒

是否释放锁

还没获取到锁

wait() 会释放锁

wait(n) 会释放锁

jstack 中常见

waiting for monitor entry

waiting on condition / Object.wait()

sleeping / parking to wait

常见误区澄清:

Thread.sleep() 不会释放锁,但 Object.wait() 会释放锁

synchronized 获取锁失败 → BLOCKED;ReentrantLock.lock() 等待 → WAITING(因为底层用 LockSupport.park())

Java 的 IO 阻塞(如 Socket.read())在 Java 层面状态仍然是 RUNNABLE,不会变成 BLOCKED 或 WAITING,这是因为 Java 把操作系统层面的 IO 阻塞也归入了 RUNNABLE

四、常见 API 对应的状态流转速查

API 调用

状态变化

恢复条件

t.start()

NEW → RUNNABLE

-

Thread.sleep(n)

RUNNABLE → TIMED_WAITING

超时自动恢复

Object.wait()

RUNNABLE → WAITING

notify()/notifyAll()

Object.wait(n)

RUNNABLE → TIMED_WAITING

超时 或 notify()

Thread.join()

RUNNABLE → WAITING

目标线程执行完毕

Thread.join(n)

RUNNABLE → TIMED_WAITING

超时 或目标线程执行完

LockSupport.park()

RUNNABLE → WAITING

unpark() 或中断

LockSupport.parkNanos()

RUNNABLE → TIMED_WAITING

超时 或 unpark()

进入 synchronized(锁被占)

RUNNABLE → BLOCKED

锁释放后竞争成功

notify() 唤醒后

WAITING → BLOCKED

获取到锁后 → RUNNABLE

run() 执行完

RUNNABLE → TERMINATED

不可逆

面试高频追问

Java 线程状态和操作系统线程状态有什么区别?

操作系统层面线程有 5 种状态(创建、就绪、运行、阻塞、终止),Java 的 RUNNABLE 对应了 OS 的 "就绪 + 运行",Java 的 BLOCKED、WAITING、TIMED_WAITING 都对应 OS 的 "阻塞"。另外 Java 把 BIO 的阻塞也归入 RUNNABLE,而 OS 层面是 "阻塞"。

BLOCKED 和 WAITING 有什么区别?

BLOCKED 是等待获取 synchronized 锁(被动阻塞),WAITING 是主动调用 wait()/join()/park() 进入等待(主动等待)。BLOCKED 不需要别人唤醒,锁一释放就自动去抢;WAITING 必须等别人显式唤醒。

sleep() 和 wait() 的状态变化有什么不同?

sleep(n) 让线程进入 TIMED_WAITING,不释放锁;wait() 让线程进入 WAITING,会释放锁。sleep() 到时间自动恢复,wait() 需要别人 notify()。

常见面试变体

"说说 Thread.sleep() 和 Object.wait() 的区别?"

"BLOCKED 和 WAITING 有什么区别?"

"如何用 jstack 排查线程阻塞问题?"

"为什么 Java 没有区分就绪和运行两个状态?"

记忆口诀

6 种状态:新建、可运行、阻塞、等待、超时等待、终止

流转主线:NEW(出生)→ RUNNABLE(上班)→ 三种摸鱼姿势(BLOCKED 等锁、WAITING 等通知、TIMED_WAITING 等闹钟)→ RUNNABLE(继续干活)→ TERMINATED(下班)

三种等待区分:BLOCKED 被锁挡、WAITING 等人叫、TIMED_WAITING 等闹钟

总结

Java 线程有 6 种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。核心流转是创建后 start() 进入 RUNNABLE,运行过程中可能因锁竞争进入 BLOCKED,因 wait()/join()/park() 进入 WAITING,因 sleep()/wait(n) 进入 TIMED_WAITING,最终执行完毕进入 TERMINATED。重点区分三种 "停顿" 状态的触发条件和恢复方式。

相关文章

焯字的笔画及康熙笔画多少画
第三灾:蚊灾和虱灾
原来,吃辣也能是一种养生
1990年世界杯射手榜前十:斯基拉奇登顶,冠军队四人上榜都是谁?