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

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

相关推荐
努力的小雨5 分钟前
龙虾量化实战法(QClaw)
后端
橙露36 分钟前
SpringBoot 整合 MinIO:分布式文件存储上传下载
spring boot·分布式·后端
嗑嗑嗑瓜子的猫1 小时前
Java!它值得!
java·开发语言
2401_895521342 小时前
【Spring Security系列】Spring Security 过滤器详解与基于JDBC的认证实现
java·后端·spring
皮卡蛋炒饭.2 小时前
线程的概念和控制
java·开发语言·jvm
一只大袋鼠2 小时前
MyBatis 入门详细实战教程(一):从环境搭建到查询运行
java·开发语言·数据库·mysql·mybatis
小码哥_常2 小时前
大文件上传不再卡顿:Spring Boot 分片上传、断点续传与进度条实现全解析
后端
程序员老邢3 小时前
【人生底稿・番外篇 05】我的电影江湖:从录像带时代,到港片陪伴的青春岁月
java·程序人生·职场发展·娱乐
sonnet-10293 小时前
函数式接口和方法引用
java·开发语言·笔记
Bat U3 小时前
JavaEE|多线程(二)
java·开发语言