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

在 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(等待唤醒)。

相关推荐
anlogic37 分钟前
Java基础 8.18
java·开发语言
追逐时光者1 小时前
.NET 使用 MethodTimer 进行运行耗时统计提升代码的整洁性与可维护性!
后端·.net
练习时长一年1 小时前
AopAutoConfiguration源码阅读
java·spring boot·intellij-idea
你的人类朋友2 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
源码宝2 小时前
【智慧工地源码】智慧工地云平台系统,涵盖安全、质量、环境、人员和设备五大管理模块,实现实时监控、智能预警和数据分析。
java·大数据·spring cloud·数据分析·源码·智慧工地·云平台
LKAI.4 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi
HeyZoeHey4 小时前
Mybatis执行sql流程(一)
java·sql·mybatis
2301_793086874 小时前
SpringCloud 07 微服务网关
java·spring cloud·微服务
Victor3564 小时前
Redis(11)如何通过命令行操作Redis?
后端