一句话总结
Java 线程有 6 种状态(定义在 Thread.State 枚举中):NEW(新建,未 start)、RUNNABLE(可运行,包括就绪和运行中)、BLOCKED(阻塞,等待 synchronized 锁)、WAITING(无限等待,wait/join/park)、TIMED_WAITING(超时等待,sleep/wait(timeout)/join(timeout))、TERMINATED(终止)。注意 Java 的 RUNNABLE 合并了操作系统的 Ready 和 Running 两种状态。
初级理解
6 种状态一览
| 状态 | 说明 | 进入方式 |
| NEW | 线程创建但未调用 start() | new Thread() |
| RUNNABLE | 可运行状态(就绪 + 运行中) | start()、被唤醒、获取锁 |
| BLOCKED | 等待 synchronized 锁 | synchronized 竞争失败 |
| WAITING | 无限等待,需要其他线程唤醒 | wait()、join()、park() |
| TIMED_WAITING | 超时等待,到时自动唤醒 | sleep()、wait(timeout)、join(timeout) |
| TERMINATED | 线程执行完毕 | run() 方法结束 |
状态演示
public class ThreadStateDemo {
public static void main(String[] args) throws Exception {
// NEW
Thread t = new Thread(() -> {
try { Thread.sleep(1000); } catch (Exception e) {}
});
System.out.println(t.getState()); // NEW
// RUNNABLE
t.start();
System.out.println(t.getState()); // RUNNABLE
// TIMED_WAITING(sleep 中)
Thread.sleep(100);
System.out.println(t.getState()); // TIMED_WAITING
// TERMINATED
t.join();
System.out.println(t.getState()); // TERMINATED
}
}
一句话总结:NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → TERMINATED。
中级深入
完整状态转换图
┌─────────────────────────────┐
│ │
▼ │
NEW ──start()──> RUNNABLE ──run()结束──> TERMINATED
│ ▲
synchronized│ │获取到锁
竞争失败 │ │
▼ │
BLOCKED─┘
│
wait()/join() │ notify()/notifyAll()
park() │ unpark()
▼ ▲
WAITING─┘
│
sleep(timeout) │ 超时到期
wait(timeout) │ notify()/notifyAll()
join(timeout) │
parkNanos() │
▼ ▲
TIMED_WAITING─┘
BLOCKED vs WAITING 的区别
| 特性 | BLOCKED | WAITING |
| 触发方式 | synchronized 竞争锁失败 | wait()、join()、park() |
| 唤醒方式 | 持有锁的线程释放锁 | notify()、notifyAll()、unpark() |
| 是否在等待队列 | EntryList(锁竞争队列) | WaitSet(条件等待队列) |
中断响应| 不响应中断 | 响应中断(抛 InterruptedException) |
WAITING 的进入方式
// 1. Object.wait() — 进入 WAITING
synchronized (obj) {
obj.wait(); // 释放锁,进入 WAITING
}
// 唤醒:obj.notify() / obj.notifyAll()
// 2. Thread.join() — 进入 WAITING
thread.join(); // 等待 thread 执行完毕
// 唤醒:thread 执行完毕
// 3. LockSupport.park() — 进入 WAITING
LockSupport.park(); // 阻塞当前线程
// 唤醒:LockSupport.unpark(thread)
TIMED_WAITING 的进入方式
// 1. Thread.sleep() — 不释放锁!
Thread.sleep(1000); // TIMED_WAITING,1秒后自动恢复
// 2. Object.wait(timeout)
synchronized (obj) {
obj.wait(1000); // 释放锁,最多等1秒
}
// 3. Thread.join(timeout)
thread.join(1000); // 最多等1秒
// 4. LockSupport.parkNanos() / parkUntil()
LockSupport.parkNanos(1_000_000_000); // 1秒
中级要点:BLOCKED 是等 synchronized 锁,WAITING 是等 notify/join/unpark。sleep 不释放锁,wait 释放锁。
高级拓展
Java 线程状态 vs 操作系统线程状态
Java 的 RUNNABLE 合并了操作系统的 Ready(就绪,等待 CPU 调度)和 Running(运行中)两种状态。这是因为 JVM 不关心操作系统层面的调度细节。
| Java 状态 | 操作系统状态 |
| NEW | 未创建 |
| RUNNABLE | Ready + Running |
| BLOCKED | Blocked(等待锁) |
| WAITING / TIMED_WAITING | Waiting(等待事件) |
| TERMINATED | Terminated |
线程中断与状态
调用 interrupt() 不会直接改变线程状态,而是设置中断标志。线程在 WAITING/TIMED_WAITING 状态下收到中断会抛 InterruptedException 并清除中断标志,回到 RUNNABLE。
// 中断在 WAITING 状态的线程
Thread t = new Thread(() -> {
try {
Thread.sleep(10000); // TIMED_WAITING
} catch (InterruptedException e) {
// 被中断后回到 RUNNABLE
System.out.println("被中断了");
}
});
t.start();
t.interrupt(); // 线程从 TIMED_WAITING → RUNNABLE
高级加分项:知道 Java RUNNABLE 合并了 OS 的 Ready 和 Running,理解中断如何影响线程状态,能画出完整的状态转换图。
实战场景
场景一:监控线程状态
// 通过 ThreadMXBean 监控所有线程状态
ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
long[] threadIds = mxBean.getAllThreadIds();
for (long id : threadIds) {
ThreadInfo info = mxBean.getThreadInfo(id);
System.out.println(info.getThreadName() + ": " + info.getThreadState());
}
场景二:线程 dump 分析
线上排查问题时,线程 dump 中每个线程都会显示当前状态和堆栈。大量线程处于 BLOCKED 说明锁竞争激烈,大量 WAITING 可能是线程池空闲或等待通知。
常见坑
| 坑 | 原因 | 解决方案 |
| sleep 不释放锁 | sleep 时持有锁,其他线程无法进入 | 用 wait 代替(需要 synchronized) |
| wait 必须在 synchronized 中 | 否则抛 IllegalMonitorStateException | 确保在同步块中调用 wait |
| notify 后状态不立即变化 | notify 后线程从 WaitSet 移到 EntryList,仍需竞争锁 | 理解 wait→BLOCKED→RUNNABLE 的转换 |
面试模拟
Q:Java 线程有哪些状态?
A:6 种状态:NEW(新建)、RUNNABLE(可运行,合并了 OS 的 Ready 和 Running)、BLOCKED(等 synchronized 锁)、WAITING(无限等待,wait/join/park)、TIMED_WAITING(超时等待,sleep/wait(timeout))、TERMINATED(终止)。
Q:BLOCKED 和 WAITING 的区别?
A:BLOCKED 是等待 synchronized 锁,线程在 EntryList 中,锁释放后自动竞争;WAITING 是等待其他线程的通知(notify/join/unpark),线程在 WaitSet 中,需要显式唤醒。BLOCKED 不响应中断,WAITING 响应中断。
Q:sleep 和 wait 对线程状态的影响?
A:sleep 使线程进入 TIMED_WAITING,不释放锁,超时自动恢复。wait 使线程进入 WAITING(或 TIMED_WAITING),释放锁,需要 notify 唤醒。两者都会让出 CPU。