在Java中,线程的状态 是通过Thread.State
枚举明确定义的,共分为6种状态。理解这些状态及其转换关系是掌握多线程编程的基础。下面我会结合源码、流程图和实际代码示例,帮你彻底理清线程的生命周期。
一、Java线程的6种状态(Thread.State枚举)
java
public enum State {
NEW, // 线程刚创建,未启动
RUNNABLE, // 可运行状态(可能在运行或等待CPU调度)
BLOCKED, // 被阻塞(等待监视器锁)
WAITING, // 无限期等待(直到被显式唤醒)
TIMED_WAITING, // 有限期等待(自动唤醒)
TERMINATED // 线程已终止
}
二、详细状态解析与转换流程图
状态转换图:
stateDiagram-v2
[*] --> NEW
NEW --> RUNNABLE: start()
RUNNABLE --> BLOCKED: 竞争锁失败
BLOCKED --> RUNNABLE: 获取到锁
RUNNABLE --> WAITING: wait()/join()/park()
WAITING --> RUNNABLE: notify()/unpark()
RUNNABLE --> TIMED_WAITING: sleep(ms)/wait(ms)
TIMED_WAITING --> RUNNABLE: 超时/notify()
RUNNABLE --> TERMINATED: run()执行完毕
状态详解:
-
NEW(新建)
-
线程对象已创建但未调用
start()
-
示例:
javaThread thread = new Thread(() -> {}); System.out.println(thread.getState()); // 输出 NEW
-
-
RUNNABLE(可运行)
- 包含两种子状态:
- Ready:等待CPU调度(线程在就绪队列中)
- Running:正在执行(占用CPU)
- 触发条件:调用
start()
后进入该状态 - 注意:IO阻塞(如Socket读写)不会改变状态,仍为RUNNABLE
- 包含两种子状态:
-
BLOCKED(阻塞)
-
线程未能获取synchronized锁时的状态
-
示例:
javasynchronized (lock) { // 其他线程尝试进入时会阻塞 }
-
-
WAITING(无限等待)
-
需要被其他线程显式唤醒
-
触发方法:
Object.wait()
(需配合notify())Thread.join()
(等待目标线程终止)LockSupport.park()
-
示例:
javasynchronized (lock) { lock.wait(); // 进入WAITING }
-
-
TIMED_WAITING(超时等待)
-
带时间限制的等待,超时后自动唤醒
-
触发方法:
Thread.sleep(long ms)
Object.wait(long timeout)
LockSupport.parkNanos()
-
示例:
javaThread.sleep(1000); // 进入TIMED_WAITING
-
-
TERMINATED(终止)
-
线程执行完
run()
方法或抛出未捕获异常 -
示例:
javathread.start(); thread.join(); System.out.println(thread.getState()); // 输出 TERMINATED
-
三、关键状态转换的代码验证
java
public class ThreadStateDemo {
public static void main(String[] args) throws Exception {
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
lock.wait(1000); // TIMED_WAITING
} catch (InterruptedException e) {}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
try {
Thread.sleep(Long.MAX_VALUE); // TIMED_WAITING
} catch (InterruptedException e) {}
}
});
Thread t3 = new Thread(() -> {
synchronized (lock) {
// 竞争锁失败会BLOCKED
}
});
System.out.println("t1: " + t1.getState()); // NEW
t1.start();
t2.start();
Thread.sleep(50); // 确保t1/t2进入同步块
System.out.println("t1: " + t1.getState()); // TIMED_WAITING (wait(1000))
System.out.println("t2: " + t2.getState()); // TIMED_WAITING (sleep)
t3.start();
Thread.sleep(50); // 确保t3开始竞争锁
System.out.println("t3: " + t3.getState()); // BLOCKED
synchronized (lock) {
lock.notifyAll(); // 唤醒t1
}
Thread.sleep(50);
System.out.println("t1: " + t1.getState()); // TERMINATED
}
}
四、WAITING vs BLOCKED 的本质区别
状态 | 触发条件 | 唤醒方式 | 典型场景 |
---|---|---|---|
BLOCKED | 竞争synchronized锁失败 | 锁释放时系统自动分配 | 多线程竞争同步锁 |
WAITING | 主动调用等待方法 | 需其他线程显式唤醒 | 线程间协作(生产者消费者) |
五、高频面试题深度解析
-
sleep()
和wait()
的区别?sleep()
是Thread的静态方法,不释放锁,进入TIMED_WAITING;wait()
是Object的方法,释放锁,需在同步块中调用。
-
如何强制终止线程?
- 已废弃:
Thread.stop()
(会导致资源未释放) - 正确做法:通过
interrupt()
中断 + 线程内检查标志位
- 已废弃:
-
RUNNABLE
状态是否一定在运行?- 不一定!可能是就绪状态(等待CPU时间片),可用
jstack
工具查看实际运行状态。
- 不一定!可能是就绪状态(等待CPU时间片),可用
掌握这些状态转换关系后,你就能:
✅ 精准分析jstack
输出的线程堆栈
✅ 设计合理的线程协作逻辑
✅ 快速定位死锁/线程泄漏问题