面试必问!线程生命周期与状态转换详解

在 Java 并发编程中,线程(Thread) 是最核心的执行单元。很多开发者在学习多线程时,会被各种状态(NEW、RUNNABLE、WAITING 等)搞晕:线程到底有哪些生命周期?这些状态是怎么转换的?本文将结合 操作系统原理 + Java 语言规范 ,带你完整理解 线程的生命周期与状态转换


一、线程的五大生命周期

Java 线程大体可以分为 五种生命周期

  1. 新建(NEW)

    • 当使用 new Thread(...) 创建线程对象时,线程处于新建状态。
    • 此时线程尚未启动,只有调用 start() 方法,线程才会进入可运行状态。
  2. 可运行(RUNNABLE)

    • 调用 start() 之后,线程进入可运行状态。
    • 此时线程可能正在 等待 CPU 调度,也可能正在运行。
    • 注意:Java 把"就绪(Ready)"和"运行中(Running)"都统称为 RUNNABLE
  3. 阻塞(BLOCKED)

    • 当线程尝试获取 synchronized 锁 但未成功时,会进入 BLOCKED 状态,直到获得锁。
  4. 等待(WAITING / TIMED_WAITING)

    • 调用 Object.wait()Thread.join()LockSupport.park() 会进入 WAITING(无限期等待) 状态;
    • 调用 sleep(ms)wait(ms)join(ms)parkNanos() 等,会进入 TIMED_WAITING(限时等待)
  5. 终止(TERMINATED)

    • 线程执行完 run() 方法后,生命周期结束,进入终止状态。
    • 已终止的线程不能再次启动。

二、线程状态转换图

可以用一个简化的状态图来理解线程生命周期:

这张图非常直观地展示了线程在 Java 中的状态切换路径。


三、常见场景下的状态变化

1. start() 之后

java 复制代码
Thread t = new Thread(() -> System.out.println("hello"));
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE

2. sleep() 进入 TIMED_WAITING

java 复制代码
Thread t = new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
t.start();
Thread.sleep(100); // 主线程先睡一下
System.out.println(t.getState()); // TIMED_WAITING

3. wait() 进入 WAITING

java 复制代码
Object lock = new Object();
Thread t = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait(); // 无限等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
t.start();
Thread.sleep(100);
System.out.println(t.getState()); // WAITING

4. synchronized 竞争进入 BLOCKED

java 复制代码
Object lock = new Object();

Thread t1 = new Thread(() -> {
    synchronized (lock) {
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
    }
});

Thread t2 = new Thread(() -> {
    synchronized (lock) {
        System.out.println("t2 acquired lock");
    }
});

t1.start();
Thread.sleep(100); // 确保t1先拿到锁
t2.start();
Thread.sleep(100);
System.out.println(t2.getState()); // BLOCKED

四、操作系统视角 vs Java 视角

  • 操作系统层面

    • 线程会经历:新建、就绪(Ready)、运行(Running)、阻塞(Blocked)、终止(Terminated)。
    • 就绪和运行是分开的,因为 CPU 调度才会切换。
  • Java 层面

    • JDK 把 Ready + Running 合并为 RUNNABLE。
    • 引入 WAITING 和 TIMED_WAITING 区分不同等待场景。
    • 因此,Java 的 Thread.State 更偏向于开发者语义,而非操作系统真实调度。

五、开发中常见误区

  1. 误区一:线程调用 run() 就能启动

    • 错 ❌:run() 只是普通方法调用;
    • 对 ✔️:必须调用 start() 才能启动新线程。
  2. 误区二:BLOCKED 和 WAITING 一样

    • 错 ❌:BLOCKED 是锁竞争,WAITING 是主动挂起等待。
    • 对 ✔️:两者触发条件和唤醒机制完全不同。
  3. 误区三:线程终止后还能 start()

    • 错 ❌:会抛 IllegalThreadStateException
    • 对 ✔️:线程只能运行一次,想再执行要创建新对象。

六、总结

  • Java 线程生命周期包含 NEW → RUNNABLE → {BLOCKED, WAITING, TIMED_WAITING} → TERMINATED
  • 状态转换取决于 锁竞争、sleep、wait、join、park 等操作。
  • Java 的状态模型是对操作系统模型的抽象,简化了开发者理解。

理解线程生命周期,不仅能帮助我们更好地写并发程序,还能在调试时快速定位问题。例如,遇到线程卡死,可以通过 jstack 查看线程是否处于 BLOCKED (锁竞争)或 WAITING(等待唤醒)。

相关推荐
qq_195551693 分钟前
代码随想录70期day7
java·开发语言
Sam-August31 分钟前
【分布式架构实战】Spring Cloud 与 Dubbo 深度对比:从架构到实战,谁才是微服务的王者?
java·spring cloud·dubbo
麦兜*40 分钟前
MongoDB 常见错误解决方案:从连接失败到主从同步问题
java·数据库·spring boot·redis·mongodb·容器
ytadpole1 小时前
揭秘设计模式:命令模式-告别混乱,打造优雅可扩展的代码
java·设计模式
计算机学姐1 小时前
基于Python的旅游数据分析可视化系统【2026最新】
vue.js·后端·python·数据分析·django·flask·旅游
用户3721574261351 小时前
Java 教程:轻松实现 Excel 与 CSV 互转 (含批量转换)
java
叫我阿柒啊2 小时前
Java全栈开发实战:从基础到微服务的深度解析
java·微服务·kafka·vue3·springboot·jwt·前端开发
该用户已不存在2 小时前
你没有听说过的7个Windows开发必备工具
前端·windows·后端
凯尔萨厮2 小时前
Java学习笔记三(封装)
java·笔记·学习
霸道流氓气质2 小时前
Java开发中常用CollectionUtils方式,以及Spring中CollectionUtils常用方法示例
java·spring