线程的状态有哪些?它们之间是如何转换的?
参考回答
Java 中线程的状态定义在 Thread.State
枚举中,共有以下几种状态:
- NEW(新建状态):线程对象被创建后,还未调用
start()
方法。 - RUNNABLE(就绪/运行状态):线程被调用
start()
方法后,可能正在运行,也可能等待 CPU 调度。 - BLOCKED(阻塞状态):线程等待获取一个锁时进入此状态。
- WAITING(无限期等待状态):线程等待其他线程显式唤醒时进入此状态(如
Object.wait()
或Thread.join()
)。 - TIMED_WAITING(限时等待状态):线程在等待时有时间限制(如
Thread.sleep()
或Object.wait(timeout)
)。 - TERMINATED(终止状态):线程执行完毕或因异常退出,进入此状态。
线程的状态并非线性转换,而是通过特定事件在状态之间切换。
详细讲解与拓展
1. 线程的状态与转换图
NEW → RUNNABLE ↔ BLOCKED
↔ WAITING ↔ TIMED_WAITING
RUNNABLE → TERMINATED
2. 各状态详解与转换
1. NEW(新建状态)
- 进入条件:调用
new Thread()
创建线程对象。 - 退出条件:调用线程的
start()
方法。 - 注意:处于 NEW 状态的线程未分配系统资源,无法运行。
示例:
Thread thread = new Thread(() -> System.out.println("Running")); // 线程处于 NEW 状态
2. RUNNABLE(就绪/运行状态)
- 进入条件:调用
start()
后,线程进入就绪队列,等待 CPU 调度。 -
特点:线程可能正在运行,也可能等待 CPU 分配时间片。
-
退出条件:
- 等待资源:进入 BLOCKED。
- 等待通知:进入 WAITING 或 TIMED_WAITING。
- 执行结束:进入 TERMINATED。
示例:
thread.start(); // 调用 start 后,线程进入 RUNNABLE 状态
3. BLOCKED(阻塞状态)
- 进入条件:线程试图进入同步代码块,但锁已被其他线程持有。
- 退出条件:获取到锁后进入 RUNNABLE。
示例:
synchronized (lock) {
// 当前线程获取到锁
}
如果其他线程尝试获取 lock
,但锁已被占用,它们会进入 BLOCKED 状态。
4. WAITING(无限期等待状态)
- 进入条件:线程调用以下方法进入 WAITING:
Object.wait()
(无超时时间)。Thread.join()
(无超时时间)。LockSupport.park()
。
- 退出条件:
- 被其他线程显式唤醒(如
notify()
或unpark()
)。
- 被其他线程显式唤醒(如
- InterruptedException 被抛出。
示例:
synchronized (lock) {
lock.wait(); // 线程进入 WAITING 状态
}
5. TIMED_WAITING(限时等待状态)
- 进入条件:线程调用以下方法,带超时时间:
Thread.sleep(time)
。Object.wait(time)
。Thread.join(time)
。LockSupport.parkNanos(time)
或parkUntil(time)
。
- 退出条件:
- 时间到期。
- 被显式唤醒(如
notify()
或unpark()
)。
示例:
Thread.sleep(1000); // 当前线程进入 TIMED_WAITING 状态
6. TERMINATED(终止状态)
- 进入条件:线程执行完
run()
方法,或者线程抛出未捕获异常。 - 特点:线程终止后不可再次启动,否则会抛出
IllegalThreadStateException
。 - 注意:终止状态的线程已经释放所有资源。
示例:
thread.join(); // 等待线程进入 TERMINATED 状态
3. 示例代码:观察线程状态
public class ThreadStateExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000); // TIMED_WAITING
synchronized (ThreadStateExample.class) {
ThreadStateExample.class.wait(); // WAITING
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("State: " + thread.getState()); // NEW
thread.start();
System.out.println("State: " + thread.getState()); // RUNNABLE
Thread.sleep(500);
System.out.println("State: " + thread.getState()); // TIMED_WAITING
synchronized (ThreadStateExample.class) {
ThreadStateExample.class.notify();
}
thread.join();
System.out.println("State: " + thread.getState()); // TERMINATED
}
}
4. 状态转换的注意事项
-
RUNNABLE 不等于运行中:线程处于 RUNNABLE 状态时,可能等待 CPU 调度,未必实际在执行。
-
BLOCKED 与 WAITING 的区别:
- BLOCKED:等待进入同步块,未获取锁。
- WAITING:线程等待显式唤醒。
- 不可重复启动:线程从 TERMINATED 状态不可再次启动。
5. 总结
- Java 的线程有 6 种状态,主要通过方法调用和线程调度切换。
- 理解线程状态有助于调试并发程序,尤其是定位死锁或阻塞问题。
- 可以通过
Thread.getState()
方法监控线程状态,结合同步工具(如锁和wait/notify
)合理设计多线程程序。