【线程的几种状态】
Java线程的6种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)是理解多线程编程的核心。本文深入解析每种状态的特点及转换条件:RUNNABLE包含I/O阻塞却不等于正在运行;BLOCKED专指synchronized锁竞争;WAITING/TIMED_WAITING实现线程协作。
💡 摘要:你是否曾被
RUNNABLE状态迷惑——它为何包含了“阻塞”?
是否在排查线程池时,看到WAITING状态却不知其因?
Java 线程的 6 种状态(NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED)
不仅是枚举值,更是理解 JVM 线程模型、锁竞争、协作机制的钥匙。
本文将从基础到深入,结合代码、图解、jstack实战,
彻底讲清每种状态的含义、转换条件、监控方法与常见误区。
文末附高清状态转换图与面试高频问题清单,助你真正掌握多线程核心基础。
一、从“线程是什么”说起
在深入状态前,先明确:线程是 CPU 调度的基本单位。
- 一个 Java 程序启动,JVM 会创建一个
main线程。 - 你可以创建更多线程,让任务并发执行。
- 但 CPU 核心数有限,操作系统需要在多个线程间快速切换,造成“同时运行”的假象。
🔑 线程状态的本质:
描述线程在 JVM 和操作系统调度 下的当前所处阶段。
二、Java 线程状态全景
Java 定义了 6 种线程状态,位于 java.lang.Thread.State 枚举中:
public enum State {
NEW, // 新建
RUNNABLE, // 可运行
BLOCKED, // 阻塞
WAITING, // 无限期等待
TIMED_WAITING, // 限期等待
TERMINATED // 终止
}
✅ 重要提示:
这是 JVM 层面的抽象状态,与操作系统的线程状态(如 running, ready, waiting)不完全等价。
特别是RUNNABLE,它包含了操作系统的 ready(就绪)和 running(运行)两种状态。
三、逐个击破:6 种状态详解
1. NEW(新建)——生命的起点
- 含义:线程对象已创建,但尚未调用
start()。 - 特点:
- 线程还未被 JVM 纳入调度。
- 此时调用
getState()可返回NEW。
Thread t = new Thread(() -> System.out.println("Hello"));
System.out.println(t.getState()); // 输出:NEW
t.start(); // 调用后,状态将改变
✅ 生命周期的第一步。
2. RUNNABLE(可运行)——CPU 的“候选者”
- 含义:线程正在 JVM 中执行,或正等待 CPU 分配时间片。
- 关键理解(易错点!):
RUNNABLE≠ 正在运行!- 它包含两种 OS 状态:
- ready:已准备好,排队等 CPU
- running:正在 CPU 上执行
- I/O 阻塞(如读文件、网络请求)也属于
RUNNABLE!
因为 JVM 无法区分线程是在计算还是在等 I/O。
// 示例 1:CPU 密集型(running)
Thread cpuTask = new Thread(() -> {
long sum = 0;
for (int i = 0; i < Integer.MAX_VALUE; i++) sum++;
}); // 状态:RUNNABLE
// 示例 2:I/O 操作(看似阻塞,但状态仍是 RUNNABLE)
Thread ioTask = new Thread(() -> {
try (FileInputStream fis = new FileInputStream("large.log")) {
fis.readAllBytes(); // I/O 阻塞中,但 getState() == RUNNABLE
} catch (IOException e) { e.printStackTrace(); }
});
🔥 面试常考:为什么 I/O 阻塞的线程状态是
RUNNABLE?
答:JVM 的线程状态模型未细分 I/O 阻塞,只要线程未进入wait/sleep/等锁,就视为“可运行”。
3. BLOCKED(阻塞)——锁的竞争者
- 含义:线程试图获取一个监视器锁(monitor)失败,等待进入
synchronized块/方法。 - 触发场景:
- 尝试进入一个被其他线程持有的
synchronized方法或代码块。 - 从
WAITING状态被唤醒后,重新竞争锁失败。
- 尝试进入一个被其他线程持有的
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
System.out.println("t1 持有锁,开始休眠...");
try { Thread.sleep(3000); } catch (InterruptedException e) {}
System.out.println("t1 释放锁");
}
});
Thread t2 = new Thread(() -> {
System.out.println("t2 尝试获取锁...");
synchronized (lock) { // t2 在此处进入 BLOCKED 状态
System.out.println("t2 终于获得锁!");
}
});
t1.start();
Thread.sleep(500);
t2.start(); // t2 会因锁被 t1 占有而进入 BLOCKED
✅ BLOCKED 的核心是
synchronized锁的竞争。
4. WAITING(无限期等待)——协作的等待者
- 含义:线程无限期等待另一个线程执行特定操作来唤醒它。
- 进入方式(调用以下方法,无超时参数):
Object.wait()Thread.join()(无超时)LockSupport.park()
- 唤醒方式:
Object.notify()/notifyAll()- 被其他线程中断(
interrupt()) LockSupport.unpark()
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("t1 进入等待...");
lock.wait(); // t1 进入 WAITING 状态,释放锁
System.out.println("t1 被唤醒!");
} catch (InterruptedException e) { e.printStackTrace(); }
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println("t2 即将唤醒 t1");
lock.notify(); // 唤醒 t1
}
});
t1.start();
Thread.sleep(1000);
t2.start();
✅
WAITING状态的线程不消耗 CPU,是线程间协作的基础。
5. TIMED_WAITING(限期等待)——有耐心的等待者
- 含义:线程等待一段时间,时间到后自动唤醒。
- 进入方式(带超时参数):
Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(long nanos)
- 唤醒方式:
- 超时自动唤醒
- 被中断
- 显式唤醒(如
notify)
Thread t = new Thread(() -> {
try {
System.out.println("开始休眠 2 秒...");
Thread.sleep(2000); // 进入 TIMED_WAITING
System.out.println("休眠结束!");
} catch (InterruptedException e) { e.printStackTrace(); }
});
✅ TIMED_WAITING 是
WAITING的“限时版”。
6. TERMINATED(终止)——生命的终点
- 含义:线程的
run()方法已执行完毕,或因未捕获异常而退出。 - 特点:
- 线程对象依然存在,但已“死亡”。
- 无法再次
start()(会抛IllegalThreadStateException)。
Thread t = new Thread(() -> {
System.out.println("任务完成");
});
t.start();
t.join(); // 等待 t 结束
System.out.println(t.getState()); // 输出:TERMINATED
四、线程状态转换图(高清版)

✅ 核心逻辑:
RUNNABLE是中心枢纽。BLOCKED专为synchronized锁设计。WAITING和TIMED_WAITING用于线程协作。
五、实战:如何监控线程状态?
1. 代码中获取状态:getState()
Thread t = new Thread(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
System.out.println("NEW: " + t.getState());
t.start();
System.out.println("启动后: " + t.getState()); // 可能是 RUNNABLE
Thread.sleep(100);
System.out.println("休眠中: " + t.getState()); // TIMED_WAITING
t.join();
System.out.println("结束后: " + t.getState()); // TERMINATED
⚠️ 注意:
getState()是瞬时快照,可能不精确。
2. 生产环境利器:jstack
# 1. 查找 Java 进程 ID
jps
# 2. 输出线程栈和状态
jstack <pid>
输出片段:
"main" #1 prio=5 os_prio=0 cpu=15.62ms elapsed=4.32s tid=0x000002aab8019000 nid=0x5a44 waiting on condition [0x000000b8c5fff000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@17.0.8/Native Method)
at Main.main(Main.java:5)
🔥
jstack是诊断死锁、性能瓶颈的必备工具。
3. 线程池中的状态
线程池中的工作线程(worker)在空闲时会调用 workQueue.take(),进入 WAITING 状态,等待新任务。
六、常见问题与面试解析
❓1. RUNNABLE 为什么包含 I/O 阻塞?
答:JVM 的线程状态模型是简化的。
只要线程没有调用wait、sleep或进入synchronized竞争锁,
即使它在等待 I/O,JVM 也认为它处于“可运行”状态。
这也是jstack中大量线程显示RUNNABLE的原因。
❓2. BLOCKED 和 WAITING 的本质区别?
答:
BLOCKED:因锁竞争失败而被动阻塞(synchronized)。WAITING:因主动协作而等待(wait/join),需其他线程显式唤醒。- 关键:
WAITING会释放锁,BLOCKED不会。
❓3. sleep() 和 wait() 的状态与锁行为?
答:
方法 状态 是否释放锁 调用位置 sleep()TIMED_WAITING否 任意位置 wait()WAITING是 必须在 synchronized块内
❓4. 线程终止后能重启吗?
答:不能。
线程是“一次性”的。终止后再次start()会抛IllegalThreadStateException。
应使用线程池或创建新线程。
❓5. 如何判断线程是否活跃?
答:使用
thread.isAlive()。
当线程处于RUNNABLE,BLOCKED,WAITING,TIMED_WAITING时返回true。
七、总结
| 状态 | 触发条件 | 关键点 |
|---|---|---|
NEW |
new Thread() |
未启动 |
RUNNABLE |
start() / I/O / 计算 |
包含就绪、运行、I/O 阻塞 |
BLOCKED |
synchronized 竞争锁 |
锁竞争 |
WAITING |
wait() / join() (无超时) |
主动协作,需唤醒 |
TIMED_WAITING |
sleep() / wait(timeout) |
限期等待,自动唤醒 |
TERMINATED |
run() 结束 |
生命周期结束 |
✅ 掌握线程状态,是理解并发编程的第一步。
动手实践,结合jstack分析,你将对多线程有更深的理解。
更多推荐
所有评论(0)