Java线程的生命周期就像 “人的一天” ,从出生到结束,经历不同状态。线程共有 6种状态(定义在 Thread.State 枚举中),核心流程如下:
1. 新建状态(NEW) → “刚出生”
-
触发条件:线程对象被创建(
new Thread()),但还没调用start()。 -
特点:还没开始工作,只是个空壳。
java
复制
Thread thread = new Thread(() -> System.out.println("干活!")); System.out.println(thread.getState()); // 输出:NEW
2. 可运行状态(RUNNABLE) → “准备好跑步”
-
触发条件:调用
start()方法后,线程进入就绪队列,等待CPU分配时间片。 -
特点:
-
可能在运行(CPU时间片到手),也可能在排队等CPU(就绪)。
-
这是线程的“活跃状态”,要么正在干活,要么随时能干活。
thread.start(); System.out.println(thread.getState()); // 输出:RUNNABLE -
3. 阻塞状态(BLOCKED) → “堵在门口等钥匙”
-
触发条件:线程试图获取某个对象的锁(如
synchronized代码块),但锁被其他线程占用。 -
例子:
-
线程A进厕所锁门了,线程B只能在门外干等。
synchronized (lock) { // 线程A拿到锁,线程B在锁外等待 → BLOCKED } -
4. 无限等待状态(WAITING) → “等朋友来叫”
-
触发条件:线程主动调用以下方法,释放锁并进入等待:
object.wait():等别人通知(notify())。thread.join():等另一个线程结束。
-
特点:一直等,直到被明确唤醒。
synchronized (lock) { lock.wait(); // 进入WAITING状态 }
5. 超时等待状态(TIMED_WAITING) → “等,但有闹钟”
-
触发条件:调用带超时参数的方法:
Thread.sleep(时间)object.wait(超时时间)thread.join(超时时间)
-
特点:等一段时间后自动醒,或中途被唤醒。
Thread.sleep(1000); // 睡1秒 → TIMED_WAITING
6. 终止状态(TERMINATED) → “下班了”
-
触发条件:线程的
run()方法执行完毕,或异常终止。 -
特点:线程彻底结束,无法重启(调用
start()会抛异常)。thread.start(); thread.join(); // 等线程结束 System.out.println(thread.getState()); // 输出:TERMINATED
生命周期流程图
NEW
↓
start()
↓
RUNNABLE ←──────┐
| 阻塞(抢锁失败)
| ↓
| BLOCKED
|
|── wait()/join() → WAITING
|
|── sleep(ms)/wait(ms) → TIMED_WAITING
↓
TERMINATED
关键区别总结
| 状态 | 触发条件 | 能否自动恢复 |
|---|---|---|
| BLOCKED | 抢不到锁 | 锁释放后自动竞争 |
| WAITING | 调用 wait()/join() | 必须等 notify()/join完成 |
| TIMED_WAITING | 调用带超时的方法(如 sleep(1000)) | 时间到或中途被唤醒 |
常见问题
-
线程卡在
RUNNABLE但没执行?- 正常现象,说明线程在就绪队列等待CPU时间片。
-
WAITING和BLOCKED的区别?BLOCKED是抢不到锁被堵住,WAITING是主动释放锁并等待通知。
-
如何避免线程永久阻塞?
- 用
TIMED_WAITING替代WAITING,设置超时时间。
- 用
口诀:
「线程一生六状态,新建就绪阻塞等
抢锁失败会阻塞,主动等待需人叫
超时等待设闹钟,任务完成就下班!」