深入解析 Java 线程的生命周期
Java 线程的六种状态定义在NEW, // 新建,尚未启动RUNNABLE, // 可运行(就绪或运行中)BLOCKED, // 阻塞(等待锁)WAITING, // 无限等待TIMED_WAITING, // 限期等待TERMINATED // 已终止注意:Java 将操作系统层面的“就绪”和“运行”统一为RUNNABLE状态。fill:#333;important;important;fil
深入解析 Java 线程的生命周期
|
🌺The Begin🌺点点关注,收藏不迷路🌺
|
1. 引言:线程也有“生老病死”
在 Java 多线程编程中,我们经常创建线程、启动线程,但很少思考:线程从创建到销毁,究竟经历了哪些状态?状态之间又是如何转换的?
理解线程的生命周期,就像理解人的生命阶段一样重要。只有掌握了线程在不同状态下的行为,才能写出正确、高效的并发程序。
本文将用流程图、源码分析和实战代码,全面剖析 Java 线程的六大状态及其转换规则。
2. 一图看懂:线程生命周期全景图

3. 六大状态的官方定义
Java 线程的六种状态定义在 java.lang.Thread.State 枚举中:
public enum State {
NEW, // 新建,尚未启动
RUNNABLE, // 可运行(就绪或运行中)
BLOCKED, // 阻塞(等待锁)
WAITING, // 无限等待
TIMED_WAITING, // 限期等待
TERMINATED // 已终止
}
注意:Java 将操作系统层面的“就绪”和“运行”统一为 RUNNABLE 状态。
4. 逐个解析:六大状态详解
4.1 NEW:新生状态
线程对象已创建,但尚未调用 start() 方法。
Thread thread = new Thread(() -> System.out.println("Hello"));
System.out.println(thread.getState()); // NEW
特征:
- 只是一个普通的 Java 对象
- 尚未与操作系统线程关联
- 不能执行任何代码
4.2 RUNNABLE:就绪/运行状态
调用 start() 后进入此状态,表示线程可以运行或正在运行。
Thread thread = new Thread(() -> {
System.out.println("Running...");
});
thread.start();
System.out.println(thread.getState()); // RUNNABLE
特征:
- 可能正在执行,也可能在等待 CPU 时间片
- Java 不区分“就绪”和“运行”
- 这是线程的正常工作状态
4.3 BLOCKED:阻塞状态
线程在等待获取锁(synchronized)时进入此状态。
public class BlockedDemo {
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (lock) {
while (true) {} // 死循环持有锁
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) { // 等待t1释放锁
System.out.println("Will not reach here");
}
});
t1.start();
Thread.sleep(100); // 确保t1先获得锁
t2.start();
Thread.sleep(100);
System.out.println("t1 state: " + t1.getState()); // RUNNABLE
System.out.println("t2 state: " + t2.getState()); // BLOCKED
}
}
特征:
- 等待
synchronized锁 - 不会响应中断(除非使用
Lock) - 锁释放后自动进入 RUNNABLE
4.4 WAITING:无限等待状态
线程等待其他线程执行特定操作(通知),进入无限等待。

public class WaitingDemo {
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread waiter = new Thread(() -> {
synchronized (lock) {
try {
lock.wait(); // 进入 WAITING 状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waiter.start();
Thread.sleep(100); // 确保wait已执行
System.out.println(waiter.getState()); // WAITING
}
}
触发 WAITING 的方法:
| 方法 | 等待条件 | 唤醒方式 |
|---|---|---|
Object.wait() |
等待 notify/notifyAll | notify()/notifyAll() |
Thread.join() |
等待目标线程死亡 | 目标线程结束 |
LockSupport.park() |
等待 unpark | unpark() |
4.5 TIMED_WAITING:限期等待状态
与 WAITING 类似,但有等待时间限制。
public class TimedWaitingDemo {
public static void main(String[] args) throws InterruptedException {
Thread timedWaiter = new Thread(() -> {
try {
Thread.sleep(5000); // sleep 5秒,进入 TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
});
timedWaiter.start();
Thread.sleep(100);
System.out.println(timedWaiter.getState()); // TIMED_WAITING
}
}
触发 TIMED_WAITING 的方法:
| 方法 | 说明 |
|---|---|
Thread.sleep(millis) |
休眠指定时间 |
wait(timeout) |
等待指定时间或通知 |
join(millis) |
等待目标线程指定时间 |
parkNanos(nanos) |
限期等待 unpark |
parkUntil(deadline) |
等待到绝对时间点 |
4.6 TERMINATED:终止状态
线程执行完毕或异常退出后的状态。
Thread thread = new Thread(() -> System.out.println("Done"));
thread.start();
thread.join(); // 等待执行完成
System.out.println(thread.getState()); // TERMINATED
特征:
- 线程生命周期结束
- 不能再次调用
start() - 线程对象仍然存在,可以查询状态
5. 状态转换的完整流程
6. 深入源码:状态追踪
6.1 Thread 类中的状态相关方法
public class Thread {
// 获取当前线程状态
public State getState() {
return jdk.internal.misc.VM.toThreadState(threadStatus);
}
// 判断线程是否存活(不是 NEW 和 TERMINATED)
public final native boolean isAlive();
// 等待线程终止
public final void join() throws InterruptedException {
join(0); // join(0) 表示无限等待
}
// 让出 CPU(从 Running -> Runnable)
public static native void yield();
}
6.2 实现一个状态监控器
public class ThreadStateMonitor {
private final Thread thread;
private volatile State lastState;
public ThreadStateMonitor(Thread thread) {
this.thread = thread;
this.lastState = thread.getState();
}
public void startMonitoring() {
Thread monitor = new Thread(() -> {
while (thread.getState() != State.TERMINATED) {
State currentState = thread.getState();
if (currentState != lastState) {
System.out.printf("[%s] %s -> %s%n",
thread.getName(), lastState, currentState);
lastState = currentState;
}
try {
Thread.sleep(10); // 每10ms检查一次
} catch (InterruptedException e) {
break;
}
}
System.out.printf("[%s] TERMINATED%n", thread.getName());
});
monitor.setDaemon(true);
monitor.start();
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(500); // TIMED_WAITING
synchronized (ThreadStateMonitor.class) {
Thread.sleep(500); // RUNNABLE
}
} catch (InterruptedException e) { }
}, "Worker");
ThreadStateMonitor monitor = new ThreadStateMonitor(t);
monitor.startMonitoring();
t.start();
t.join();
}
}
7. 常见误区与对比
7.1 误区一:RUNNABLE = 正在运行?
// 这个线程在长时间 I/O 时,状态仍然是 RUNNABLE
Thread ioThread = new Thread(() -> {
try {
// 从慢速网络读取数据
URL url = new URL("http://very-slow-server.com");
InputStream in = url.openStream();
int data = in.read(); // 阻塞等待数据
} catch (IOException e) { }
});
解释:Java 层面的 I/O 阻塞不改变线程状态,JVM 认为线程仍在等待 CPU,只是操作系统将其挂起。
7.2 误区二:BLOCKED vs WAITING
| 方面 | BLOCKED | WAITING |
|---|---|---|
| 等待对象 | synchronized 锁 | 其他线程的通知 |
| 是否可中断 | 否 | 是(interrupt 可唤醒) |
| 典型场景 | 锁竞争 | wait/join/park |
| 唤醒方式 | 锁释放 | notify/unpark/线程结束 |
7.3 误区三:yield 会改变状态?
Thread.yield(); // 不会改变线程状态
yield() 只是提示调度器:当前线程愿意让出 CPU。线程仍然处于 RUNNABLE 状态,只是从“运行”变为“就绪”。
8. 实战:线程状态的可视化
8.1 创建各种状态的线程
public class ThreadStateDemo {
public static void main(String[] args) throws InterruptedException {
// NEW 状态
Thread newThread = new Thread(() -> {});
System.out.println("1. NEW: " + newThread.getState());
// RUNNABLE 状态
Thread runnableThread = new Thread(() -> {
while (true) {
// 死循环,保持运行
}
});
runnableThread.start();
System.out.println("2. RUNNABLE: " + runnableThread.getState());
// BLOCKED 状态
Object lock = new Object();
Thread holder = new Thread(() -> {
synchronized (lock) {
try { Thread.sleep(10000); } catch (InterruptedException e) {}
}
});
Thread blockedThread = new Thread(() -> {
synchronized (lock) {
System.out.println("Got lock");
}
});
holder.start();
Thread.sleep(100);
blockedThread.start();
Thread.sleep(100);
System.out.println("3. BLOCKED: " + blockedThread.getState());
// WAITING 状态
Thread waitingThread = new Thread(() -> {
synchronized (lock) {
try { lock.wait(); } catch (InterruptedException e) {}
}
});
waitingThread.start();
Thread.sleep(100);
System.out.println("4. WAITING: " + waitingThread.getState());
// TIMED_WAITING 状态
Thread timedThread = new Thread(() -> {
try { Thread.sleep(10000); } catch (InterruptedException e) {}
});
timedThread.start();
Thread.sleep(100);
System.out.println("5. TIMED_WAITING: " + timedThread.getState());
// TERMINATED 状态
Thread terminatedThread = new Thread(() -> {});
terminatedThread.start();
terminatedThread.join();
System.out.println("6. TERMINATED: " + terminatedThread.getState());
}
}
8.2 输出结果
1. NEW: NEW
2. RUNNABLE: RUNNABLE
3. BLOCKED: BLOCKED
4. WAITING: WAITING
5. TIMED_WAITING: TIMED_WAITING
6. TERMINATED: TERMINATED
9. 状态转换常见问题排查
9.1 线程为什么一直处于 RUNNABLE?
// 可能原因1:死循环
while(true) { }
// 可能原因2:高 CPU 计算
BigInteger.probablePrime(2048, new Random());
// 可能原因3:JNI 调用卡住
nativeMethod(); // 状态不会改变
// 可能原因4:网络 I/O(底层 socket 读取)
socket.getInputStream().read(); // 仍是 RUNNABLE
9.2 线程为什么一直处于 WAITING?
// 可能原因1:object.wait() 后无人 notify
synchronized(obj) {
obj.wait(); // 永远等待
}
// 可能原因2:thread.join() 的目标线程无限循环
Thread target = new Thread(() -> { while(true); });
target.start();
target.join(); // 永远等待
// 可能原因3:线程池的等待队列
ExecutorService pool = Executors.newFixedThreadPool(1);
Future<?> future = pool.submit(() -> { while(true); });
future.get(); // 永远等待
10. 总结与速查表
10.1 线程状态速查表
| 状态 | 英文 | 如何进入 | 如何离开 |
|---|---|---|---|
| 新建 | NEW | new Thread() |
start() |
| 可运行 | RUNNABLE | start() |
等待 CPU/锁/通知 |
| 阻塞 | BLOCKED | 等待 synchronized 锁 |
获得锁 |
| 无限等待 | WAITING | wait()/join()/park() |
notify()/线程结束/unpark() |
| 限期等待 | TIMED_WAITING | sleep(t)/wait(t)/join(t)/parkNanos() |
超时/通知 |
| 终止 | TERMINATED | run() 结束 |
无法离开 |
10.2 关键要点
一句话总结:
Java 线程有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED 六种状态。理解这些状态及其转换规则,是编写正确并发程序的基础。其中 RUNNABLE 包含了操作系统层面的“就绪”和“运行”,而
synchronized锁等待导致 BLOCKED,wait()/join()/park()导致 WAITING,带有超时参数的方法导致 TIMED_WAITING。
📌 调试技巧:使用
jstack <pid>或Thread.getAllStackTraces()可以查看所有线程的状态,是排查死锁、线程卡死问题的利器。
如果觉得本文对你有帮助,欢迎点赞、收藏、转发~

|
🌺The End🌺点点关注,收藏不迷路🌺
|
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)