2. 线程生命周期状态观测
线程状态观测的核心思路
Java 线程在 Thread.State 枚举中定义了 6 种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。要观测这些状态,关键是让线程在受控条件下进入每种状态,再用 getState() 读取,并用线程转储(jstack 或 Thread.getAllStackTraces())交叉验证。
让线程进入各状态的受控代码
下面这段程序用一个共享锁对象和多个线程,依次触发 BLOCKED、WAITING、TIMED_WAITING 状态,并在主线程中轮询打印状态变化。
import java.util.concurrent.TimeUnit;
public class ThreadStateDemo {
static final Object LOCK = new Object();
public static void main(String[] args) throws Exception {
// 1. NEW 状态
Thread t = new Thread(() -> {
// 3. RUNNABLE 状态(进入 run 后)
synchronized (LOCK) {
try {
// 4. WAITING 状态:wait() 无超时
LOCK.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "state-demo");
System.out.println("[1] 创建后: " + t.getState()); // NEW
// 2. start() 后进入 RUNNABLE
t.start();
Thread.sleep(50);
System.out.println("[2] start后: " + t.getState()); // RUNNABLE 或 WAITING
// 5. 让另一个线程持有锁,使 t 进入 BLOCKED
Thread holder = new Thread(() -> {
synchronized (LOCK) {
try { Thread.sleep(800); } catch (InterruptedException ignored) {}
}
}, "lock-holder");
holder.start();
Thread.sleep(100);
System.out.println("[3] 锁被占时: " + t.getState()); // BLOCKED
// 6. TIMED_WAITING 演示
Thread sleeper = new Thread(() -> {
try { Thread.sleep(2000); } catch (InterruptedException ignored) {}
}, "sleeper");
sleeper.start();
Thread.sleep(100);
System.out.println("[4] sleep中: " + sleeper.getState()); // TIMED_WAITING
// 7. 唤醒 t,观察回到 RUNNABLE 再到 TERMINATED
synchronized (LOCK) { LOCK.notifyAll(); }
t.join();
System.out.println("[5] 结束后: " + t.getState()); // TERMINATED
// 8. 线程转储验证
Thread.getAllStackTraces().forEach((th, stack) -> {
if (th.getName().startsWith("state-demo") || th.getName().startsWith("sleeper")) {
System.out.println("转储: " + th.getName() + " -> " + th.getState());
}
});
}
}
关键点:RUNNABLE 在 Java 中同时涵盖“就绪”和“运行中”两种操作系统层面状态,因为 JVM 不区分线程是否已获得 CPU 时间片。因此观测时看到 RUNNABLE 并不代表线程一定在执行,也可能在等待 CPU 调度。
状态转换条件速查
| 起始状态 | 触发动作 | 目标状态 | 恢复条件 |
|---|---|---|---|
| NEW | 调用 start() | RUNNABLE | — |
| RUNNABLE | 竞争 synchronized 锁失败 | BLOCKED | 持有锁的线程释放锁 |
| RUNNABLE | 调用 wait() / join() / LockSupport.park() | WAITING | notify()/notifyAll() 或被 join 线程结束 |
| RUNNABLE | 调用 sleep(ms) / wait(ms) / join(ms) | TIMED_WAITING | 超时到期或被唤醒 |
| RUNNABLE | run() 正常返回或抛出未捕获异常 | TERMINATED | 不可逆 |
注意:BLOCKED 仅针对 synchronized 锁竞争。使用
ReentrantLock 等 java.util.concurrent 锁时,等待锁的线程状态是 WAITING 或 TIMED_WAITING,而非 BLOCKED。这是观测时容易混淆的地方。
验证与判读
- 运行程序后,控制台应依次输出 NEW → RUNNABLE/WAITING → BLOCKED → TIMED_WAITING → TERMINATED 的状态序列。
- 若
[3]处输出不是 BLOCKED,检查holder线程是否已先于t获得锁,可适当增大Thread.sleep(100)的等待时间。 - 用
jstack <pid>在程序运行期间抓取转储,搜索线程名state-demo,应能看到java.lang.Thread.State: WAITING (on object monitor)或BLOCKED (on object monitor)字样。 - 线程终止后再次调用
getState()始终返回 TERMINATED,且isAlive()返回 false,可作为终止状态的辅助判据。