1.Java线程状态概述
Java 线程的生命周期由Thread.State枚举明确规定,共 6 种状态,分别是:
- 新建状态(New)
- 可运行状态(Runnable)
- 阻塞状态(Blocked)
- 等待状态(Waiting)
- 超时等待状态(Timed_Waiting)
- 终止状态(Terminated)
这 6 种状态构成了 Java 线程的完整生命周期,线程在运行过程中会在这些状态之间转换(除了新建和终止状态,其他状态可相互转换)。
2. 6 种核心状态详细说明
1. 新建状态(New)
- 定义 :当创建了
Thread类的实例对象,但尚未调用start()方法时,线程处于新建状态。 - 核心特征 :
- 此时线程仅为一个 Java 对象,未被 JVM 真正启动,也未分配操作系统级别的线程资源(如栈空间、程序计数器等)。
- 线程尚未进入线程调度队列,无法被 CPU 调度执行。
- 触发条件 :通过
new Thread(...)创建线程实例(无论继承 Thread 类还是实现 Runnable 接口),未调用start()。 - 示例 :
Thread thread = new Thread(() -> {});(此时 thread 处于 New 状态) - 状态转换 :仅能通过调用
thread.start()方法,从「新建状态」转换为「可运行状态(Runnable)」,且start()方法仅能调用一次(重复调用会抛出IllegalThreadStateException)。
2.可运行状态(Runnable)
- 定义 :调用
start()方法后,线程进入可运行状态,这是 Java 虚拟机层面合并后的状态,对应操作系统层面的两个状态:就绪状态 和 运行状态。 - 核心特征 :
- 就绪状态:线程已被 JVM 启动,分配了系统资源,加入线程调度队列,等待 CPU 分配时间片(此时线程并未真正执行)。
- 运行状态:CPU 为线程分配了时间片,线程正在执行
run()方法中的业务逻辑。 - Java 虚拟机不区分这两种状态,统一归为
Runnable,因为线程在就绪和运行之间的切换由 CPU 调度器决定,JVM 无法干预。
- 触发条件 :
- 新建状态线程调用
start()方法,进入 Runnable 状态(就绪)。 - 阻塞状态 / 等待状态 / 超时等待状态的线程被唤醒 / 获取锁 / 超时后,会进入 Runnable 状态(就绪)。
- 新建状态线程调用
- 状态转换 :
- Runnable → Blocked:线程竞争
synchronized对象锁失败时(等待锁释放)。 - Runnable → Waiting:调用无参的
Object.wait()、Thread.join()、LockSupport.park()方法。 - Runnable → Timed_Waiting:调用带超时参数的
Thread.sleep(long)、Object.wait(long)等方法。 - Runnable → Terminated:
run()方法正常执行完毕,或线程因未捕获异常终止。
- Runnable → Blocked:线程竞争
3.阻塞状态(Blocked)
- 定义 :线程因 ** 等待获取对象监视器锁(synchronized 锁)** 而被阻塞的状态,仅与
synchronized关键字相关。 - 核心特征 :
- 线程此时无法执行代码,只能等待其他持有
synchronized锁的线程释放锁。 - 该状态仅针对
synchronized锁,若使用java.util.concurrent包下的 Lock 锁(如 ReentrantLock),线程竞争锁失败时会进入「等待状态(Waiting)」,而非 Blocked 状态。
- 线程此时无法执行代码,只能等待其他持有
- 触发条件 :
- 线程尝试进入
synchronized方法 / 代码块,而锁已被其他线程持有。
- 线程尝试进入
- 状态转换 :
- Blocked → Runnable:持有
synchronized锁的线程释放锁,且当前线程成功获取到锁。 - Blocked → Terminated:线程在阻塞期间被中断(极少发生,或线程对象被回收)。
- Blocked → Runnable:持有
4.等待状态(Waiting)
- 定义 :线程进入无超时时间的等待状态,若无其他线程主动唤醒,该线程会一直等待,永不自动返回可运行状态。
- 核心特征 :
- 等待状态是 "无限期" 的,依赖其他线程的显式唤醒操作。
- 进入该状态的线程会释放已持有的锁(若有),以便其他线程执行。
- 触发条件(常见方法) :
- 调用
Object.wait()方法(无参):需在synchronized代码块中调用,线程释放对象锁,进入等待。 - 调用
Thread.join()方法(无参):等待被 join 的线程执行完毕,当前线程进入等待。 - 调用
LockSupport.park()方法:无锁关联的等待,需通过LockSupport.unpark(Thread)唤醒。
- 调用
- 状态转换 :
- Waiting → Runnable:
- 对于
Object.wait():其他线程调用该对象的Object.notify()或Object.notifyAll()方法唤醒当前线程。 - 对于
Thread.join():被 join 的线程执行完毕,当前线程自动唤醒。 - 对于
LockSupport.park():其他线程调用LockSupport.unpark(当前线程)唤醒。
- 对于
- Waiting → Terminated:线程在等待期间被中断,或线程对象被回收。
- Waiting → Runnable:
5.超时等待状态(Timed_Waiting)
- 定义 :线程进入有明确超时时间的等待状态,无需其他线程主动唤醒,超时时间到达后会自动返回可运行状态;也可在超时前被其他线程主动唤醒。
- 核心特征 :
- 等待有 "时间限制",是 Waiting 状态的超时版本。
- 进入该状态的线程同样会释放已持有的锁(除
Thread.sleep(long)外,sleep方法不会释放锁)。
- 触发条件(常见方法) :
- 调用
Thread.sleep(long millis):线程休眠指定时间,不释放任何锁,超时后自动唤醒。 - 调用
Object.wait(long millis)(带参):在synchronized代码块中调用,释放对象锁,超时自动唤醒或被notify()/notifyAll()唤醒。 - 调用
Thread.join(long millis)(带参):等待被 join 的线程执行完毕,或超时后自动唤醒。 - 调用
LockSupport.parkNanos(long nanos)/LockSupport.parkUntil(long deadline):带超时的 park 操作。
- 调用
- 状态转换 :
- Timed_Waiting → Runnable:
- 超时时间到达,线程自动唤醒。
- 超时前被其他线程主动唤醒(如
Object.notify()、LockSupport.unpark())。
- Timed_Waiting → Terminated:线程在超时等待期间被中断,或线程对象被回收。
- Timed_Waiting → Runnable:
6.终止状态(Terminated)
- 定义:线程的生命周期完全结束,线程不再具备执行能力,也无法转换为其他任何状态。
- 核心特征 :
- 线程的
run()方法执行流程终止,线程对象可能还存在(被 GC 回收前),但线程本身已失效。 - 终止后的线程无法再次调用
start()方法(调用会抛出IllegalThreadStateException)。
- 线程的
- 触发条件(两种场景) :
- 正常终止:
run()方法中的业务逻辑全部执行完毕,线程正常退出。 - 异常终止:线程在执行
run()方法时抛出未被捕获的异常(如 NullPointerException、InterruptedException 等),导致线程被迫终止。
- 正常终止:
- 状态转换:无后续状态转换,线程生命周期结束。
3.关键区分
- Runnable 状态 vs 操作系统就绪 / 运行状态:Java 的 Runnable 是合并状态,包含操作系统的 "就绪(等待 CPU 调度)" 和 "运行(正在执行)" 两种状态,由 CPU 调度器负责切换,JVM 不感知。
- Blocked vs Waiting vs Timed_Waiting :
- Blocked:仅因竞争
synchronized锁阻塞,有明确的 "锁等待" 目标。 - Waiting:无超时,需主动唤醒,释放锁(大部分场景)。
- Timed_Waiting:有超时,可自动唤醒或主动唤醒,
sleep()不释放锁,其他如wait(long)释放锁。
- Blocked:仅因竞争
- sleep() vs wait() :
sleep(long):属于 Timed_Waiting,不释放锁,静态方法(针对当前线程)。wait()/wait(long):分别属于 Waiting/Timed_Waiting,释放对象锁,实例方法(针对具体对象),需在synchronized中调用。