Java 线程状态

线程状态

一、操作系统的线程状态

操作系统层面,线程状态经典模型可以概括为 "三态为主,五态展开"

核心三态

  • 就绪态(Ready):线程已具备运行条件,正在等待 CPU 调度,经调度程序选中后进入 Running 状态。
  • 运行态(Running):线程正在实际占用 CPU 执行。
  • 等待态(Waiting/Blocked):线程正在等待某个事件(如锁、信号量)或资源(如 I/O)完成,即使给它 CPU 也无法继续执行。

补充两态:线程被创建、分配资源后加入就绪队列,即进入 新建态(New) ;线程执行完毕后进入 终止态(Terminated)。五态合起来就是:New → Ready → Running → Blocked → Terminated。

经典转换关系图

复制代码
         创建
          │
          ▼
      ┌───────┐
      │  New  │ (新建态)
      └───┬───┘
          │ 分配资源、加入就绪队列
          ▼
      ┌─────────┐  调度器选中   ┌─────────┐
      │ Ready   │─────────────►│ Running │
      │ (就绪态) │◄─────────────│ (运行态) │
      └────┬────┘  时间片用完   └────┬────┘
           ▲                        │
           │ 等待的事件/IO完成        │ 等待I/O、锁、信号量等
           │                        ▼
           │                  ┌──────────┐
           └──────────────────│  Blocked │
                               │ (阻塞态/等待态) │
                               └──────────┘

      Running ──执行完毕/被终止──►  ┌────────────┐
                                  │ Terminated │ (终止态)
                                  └────────────┘

关键规则:Blocked 不能直接跳到 Running,必须先回到 Ready,重新参与调度后才可能拿到 CPU。


二、Java 的线程状态

核心结论

Java 线程有 6 种状态Thread.State 枚举),是 JVM 层面 的状态划分,和操作系统层面的线程状态不是一一对应 的。最典型的区别是:Java 没有单独的"运行中(Running)"状态,就绪和运行中统一归为 RUNNABLE

java 复制代码
// Thread.State 源码
public enum State {
    NEW,           // 新建状态
    RUNNABLE,      // 可运行状态
    BLOCKED,       // 阻塞状态
    WAITING,       // 等待状态
    TIMED_WAITING, // 超时等待状态
    TERMINATED     // 终止状态
}

六种状态详解

状态 含义 进入方式 典型触发 API
NEW 线程对象已创建,尚未启动 new Thread() 之后、start() 之前 ---
RUNNABLE 可运行(含"就绪"和"运行中") 调用 start() ---
BLOCKED 阻塞,等待拿 synchronized 争抢监视器锁失败 进入 synchronized 代码块/方法
WAITING 无限期等待,需别的线程唤醒 调用无参等待方法 Object.wait()Thread.join()LockSupport.park()
TIMED_WAITING 限期等待,超时自动返回 调用带超时参数的等待方法 Thread.sleep(ms)Object.wait(ms)Thread.join(ms)parkNanos()
TERMINATED 线程执行结束 run() 正常返回或抛出未捕获异常 ---

状态转换图(文字版)

复制代码
NEW  ──start()──►  RUNNABLE

RUNNABLE  ──synchronized 抢锁失败──►  BLOCKED
BLOCKED   ──获得锁──►  RUNNABLE

RUNNABLE  ──wait()/join()/park()──►  WAITING
WAITING   ──notify()/notifyAll()/目标线程结束/unpark()/中断──►  RUNNABLE

RUNNABLE  ──sleep(t)/wait(t)/join(t)──►  TIMED_WAITING
TIMED_WAITING  ──超时/被唤醒/被中断──►  RUNNABLE

RUNNABLE  ──run()执行完/抛异常──►  TERMINATED

记忆技巧:所有"离开 RUNNABLE"的箭头都是主动调用某个方法造成的;所有"回到 RUNNABLE"的箭头都是被动被唤醒/超时/抢到锁造成的。


三、OS 状态 ↔ Java 状态 对照表 ⭐️

OS 状态 对应的 Java Thread.State
New NEW
Ready(就绪) RUNNABLE(就绪部分)
Running(运行) RUNNABLE(运行部分)
Blocked(等锁/等IO/等事件,统称) BLOCKED (等 synchronized 锁)或 WAITING / TIMED_WAITING(等 wait/join/park/IO)
Terminated TERMINATED

为什么会有这种差异:

  • Java 把 OS 的 Ready 和 Running 合并 成一个 RUNNABLE,因为线程调度(CPU 时间片分配)由操作系统决定,JVM 不参与、也无法感知这个粒度。
  • Java 把 OS 笼统的 Blocked 拆分BLOCKED / WAITING / TIMED_WAITING 三种,是因为 JVM 想让开发者清楚"具体在等什么"------等锁、等条件、还是等超时。

四、高频考点

1. RUNNABLE 为什么不区分就绪和运行中?

线程调度(CPU 时间片分配)由操作系统决定,Java 虚拟机感知不到、也不需要感知这个粒度,所以统一算 RUNNABLE

2. sleep() 和 wait() 的核心区别 ⭐️

对比项 Thread.sleep() Object.wait()
所属类 Thread(静态方法) Object(实例方法)
是否释放锁 不释放 释放
是否需要 synchronized 不需要 必须在 synchronized 内调用 ,否则抛 IllegalMonitorStateException
唤醒方式 超时自动醒 notify()/notifyAll() 或超时(如果用带参版本)
对应状态 TIMED_WAITING WAITING(无参)/ TIMED_WAITING(带参)
java 复制代码
synchronized (lock) {
    Thread.sleep(1000); // 持有锁睡眠,其他线程仍然 BLOCKED,拿不到锁
    lock.wait();        // 释放锁,其他线程可以进来执行
}

3. BLOCKED 和 WAITING 的区别 ⭐️(必考)

  • BLOCKED :专指等待 synchronized 内置锁
  • WAITING / TIMED_WAITING :使用 Lock(如 ReentrantLock)、LockSupport.park()wait()join() 等方式等待时的状态,不算 BLOCKED

一句话:synchronized 抢锁失败 → BLOCKEDReentrantLock.lock() 抢锁失败 → WAITING(内部基于 AQS + LockSupport.park() 实现)。

4. 中断(interrupt)对各状态的影响

  • 线程处于 WAITING / TIMED_WAITING 时被 interrupt():会抛出 InterruptedException,线程被唤醒并回到 RUNNABLE(需要在 catch 里处理)。
  • 线程处于 RUNNABLE 时被 interrupt()不会 自动停止,只是把中断标志位置为 true,需要代码主动检查 Thread.isInterrupted() 来响应。
  • BLOCKED 状态下被中断:不会抛异常,也不会立刻退出阻塞(BLOCKED 状态对中断不敏感,直到抢到锁才会检测到中断标志)。

5. 没有"死锁"对应的状态吗?

没有专门状态。两个线程互相等待对方持有的锁,双方都会停留在 BLOCKED (或 WAITING,取决于用的锁类型),通过 jstack 可以看到线程互相 BLOCKED 并被标注 "deadlock"。

6. TERMINATED 的线程能重新 start() 吗?

不能。线程只能启动一次,重复调用 start() 会抛 IllegalThreadStateException

7. OS 的 Blocked 能不能直接变成 Running?

不能,必须先回到 Ready(就绪队列),重新参与调度后才可能拿到 CPU 进入 Running。


五、验证代码

java 复制代码
public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread t = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(500);   // -> TIMED_WAITING
                    lock.wait();          // -> WAITING
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        System.out.println(t.getState());   // NEW
        t.start();

        Thread.sleep(100);
        System.out.println(t.getState());   // TIMED_WAITING

        Thread.sleep(600);
        System.out.println(t.getState());   // WAITING

        synchronized (lock) {
            lock.notify();
        }
        t.join();
        System.out.println(t.getState());   // TERMINATED
    }
}

六、一句话总结

"操作系统层面线程有五态:New、Ready、Running、Blocked、Terminated,核心是就绪、运行、等待三态循环。Java 在此基础上做了 JVM 视角的重新划分,共 6 种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。区别主要在于两点:一是 Java 把 OS 的 Ready 和 Running 合并成了 RUNNABLE,因为 JVM 不感知 CPU 调度;二是 Java 把 OS 笼统的 Blocked 拆分成了 BLOCKED(等 synchronized 锁)和 WAITING/TIMED_WAITING(等条件、超时、IO 等),方便开发者定位问题。"


七、追问

  • 线程池中线程执行完一个任务后是什么状态?(仍是 RUNNABLE,在 getTask() 里等待新任务,不会变成 TERMINATED)
  • synchronizedReentrantLock 在状态表现上的区别?(见第四节第 3 点)
  • 如何用 jstack 排查线程状态问题?(关注 BLOCKED 线程和持锁关系,排查死锁)
  • wait()notify() 为什么要写在 synchronized 里?(保证等待和检查条件的原子性,避免"假唤醒"和竞态条件)
  • OS 的五态和七态模型区别?(七态多了 Ready Suspend / Blocked Suspend,涉及进程挂起/swap,操作系统内存管理场景才会用到,纯线程调度一般用五态即可)
相关推荐
土司大王1 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
土司大王2 小时前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
金金计较.2 小时前
Go语言-3
java·开发语言·golang
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之元注解简化权限表达式
java·数据库·spring
xifangge20253 小时前
AGENTS.md 怎么写?涵盖 Java、Python、Vue、Go 的 8 套开箱即用模板
java·vue.js·python
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之云服务集成与多因子认证设计
java·开发语言·spring
liangsheng_g4 小时前
SpringAOP拦截器链递归与事务钩子补偿源码实战
java·spring
SL_staff4 小时前
制造业私有化文档平台的技术实践:从知识孤岛到可追溯知识资产
java·spring·开源
SL_staff5 小时前
3天上线OKR系统:一名HR与1名工程师如何用JVS完成全栈交付
java·低代码·开源