Java 线程生命周期

各状态解释与转换触发条件
| 状态 | 含义 | 转换触发条件 |
|---|---|---|
| NEW(新建) | 创建了线程对象,但未调用 start() |
调用 start() 进入 Runnable |
| RUNNABLE(可运行) | 已启动线程,正在等待 CPU 调度(可能已运行) | 被操作系统调度执行代码时进入 Running |
| RUNNING(运行) | 实际占用 CPU 执行线程代码(属于 RUNNABLE 的子集) | <ul><li>执行 wait() 进入 WAITING</li><li>执行 sleep()、join()、LockSupport.parkNanos() 等进入 TIMED_WAITING</li><li>竞争锁失败进入 BLOCKED</li><li>执行完毕进入 TERMINATED</li></ul> |
| BLOCKED(阻塞) | 等待获取某个 monitor 锁(即 synchronized) |
获得锁后返回 RUNNABLE |
| WAITING(等待) | 无限期等待被其他线程唤醒(如 Object.wait()、Thread.join()、LockSupport.park()) |
被 notify()、notifyAll()、join() 线程结束唤醒进入 RUNNABLE |
| TIMED_WAITING(超时等待) | 在指定时间内等待,如 sleep(ms)、wait(ms)、join(ms)、parkNanos() |
超时时间到或被唤醒后进入 RUNNABLE |
| TERMINATED(终止) | 线程执行完 run() 方法,或异常退出 |
线程生命周期结束,不可再运行 |
状态转换总结
| 触发事件 | 状态变迁 |
|---|---|
start() 被调用 |
NEW → RUNNABLE |
| 获得 CPU 执行时间片 | RUNNABLE → RUNNING |
执行 wait() |
RUNNING → WAITING |
执行 sleep()、join(ms) |
RUNNING → TIMED_WAITING |
| 等待锁资源 | RUNNING → BLOCKED |
被 notify() 唤醒 |
WAITING → RUNNABLE |
| 超时等待结束 | TIMED_WAITING → RUNNABLE |
| 获取到锁 | BLOCKED → RUNNABLE |
run() 方法执行完毕 |
任意状态 → TERMINATED |
当然,以下是对比 sleep()、wait()、notify()、notifyAll() 的完整内容,包含它们之间的区别、锁与 CPU 资源的释放、唤醒机制等内容,已整合前面内容:
Java 中 sleep()、wait()、notify()、notifyAll() 对比
| 方法 | 所属类 | 是否释放锁 | 是否让出 CPU | 唤醒方式 | 使用前提 | 是否抛异常 |
|---|---|---|---|---|---|---|
sleep(ms) |
Thread |
❌ 否 | ✅ 是 | 自动超时唤醒 | 不需要 synchronized |
✅ 抛 InterruptedException |
wait() |
Object |
✅ 是 | ✅ 是 | notify() / notifyAll() 或超时 |
必须在 synchronized 中 |
✅ 抛 InterruptedException |
wait(ms) |
Object |
✅ 是 | ✅ 是 | 时间到了 or 被唤醒 | 必须在 synchronized 中 |
✅ |
notify() |
Object |
❌ | ❌ | 唤醒一个 wait() 线程 |
必须在 synchronized 中 |
❌ |
notifyAll() |
Object |
❌ | ❌ | 唤醒所有 wait() 线程 |
必须在 synchronized 中 |
❌ |
方法解释
Thread.sleep(ms)
- 功能:让当前线程睡眠(暂停执行)一段时间
- 不释放锁:如果持有
synchronized锁,睡眠时仍占有该锁 - 释放 CPU:当前线程暂停调度,其他线程有机会运行
- 常见用途:模拟延迟、限速、轮询等
- 异常:必须捕获或声明
InterruptedException
1
2
3
synchronized (lock) {
Thread.sleep(1000); // 不释放 lock,其他线程无法进入该锁块
}
Object.wait() / wait(ms)
- 功能:挂起线程,等待其他线程通知(或超时)
- 释放锁:调用后立即释放当前持有的
monitor - 等待队列:进入对象的等待队列,直到被
notify()/notifyAll()唤醒 - 必须在 synchronized 中使用:否则抛出
IllegalMonitorStateException1 2 3 4 5 6
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner at java.base/java.lang.Object.wait0(Native Method) at java.base/java.lang.Object.wait(Object.java:366) at com.example.demogc.Dermo1.get(Dermo1.java:23) at com.example.demogc.Dermo1$1.run(Dermo1.java:32) at java.base/java.lang.Thread.run(Thread.java:1583)
- 超时版本:可以避免永久阻塞
- 异常:会抛出
InterruptedException
1
2
3
4
5
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // 释放 lock,等待 notify 唤醒
}
}
🔹 Object.notify()
- 功能:随机唤醒一个正在
wait()的线程 - 不释放锁:notify 后当前线程继续持有锁,只有退出 synchronized 才会释放
- 唤醒机制:被唤醒线程不会立刻执行,而是进入锁竞争队列,等待重新获得锁
- 使用场景:条件满足后唤醒单个线程,例如有新数据到达队列
1
2
3
synchronized (lock) {
lock.notify(); // 唤醒一个等待中的线程
}
🔹 Object.notifyAll()
- 功能:唤醒所有等待该对象锁的线程
- 适用场景:当有多个条件依赖于某一状态变化时使用
- 机制同 notify:被唤醒线程重新竞争锁执行
1
2
3
synchronized (lock) {
lock.notifyAll(); // 通知所有等待该锁的线程
}
🔁 调用时序图(简要描述)
1
2
3
4
5
6
7
8
9
线程A:wait()
|
|---> 释放锁,进入等待队列
|
线程B:notify()
|
|---> 唤醒A,A转入阻塞队列(等待锁)
|
A获得锁后继续执行
🧠 场景类比帮助理解
| 方法 | 类比场景 |
|---|---|
sleep() |
自己设置闹钟睡觉,到点醒来,不管别人 |
wait() |
在会议室外排队等通知,暂时让出座位 |
notify() |
主持人通知某个等待的人进会议室 |
notifyAll() |
主持人通知所有等待的人都进会议室排队竞争座位 |
