线程状态概览
在 Java 中,线程的状态由 java.lang.Thread.State 枚举类定义,根据 Java 官方文档和 Java 内存模型,一个线程在任何时刻都只可能处于以下六种状态之一:

- NEW (新建)
- RUNNABLE (可运行)
- BLOCKED (阻塞)
- WAITING (等待)
- TIMED_WAITING (定时等待)
- TERMINATED (终止)
这六种状态构成了线程完整的生命周期,下面我们逐一解析每个状态的含义、如何进入该状态,以及如何从该状态转换出去。
NEW (新建状态)
- 描述:线程被创建,但尚未启动,线程只是一个对象,JVM 没有为其分配系统资源(如调用栈空间)。
- 如何进入:当你使用
new关键字创建一个Thread实例时,它就处于NEW状态。 - 如何转换:
- 调用线程对象的
start()方法,状态将变为RUNNABLE。 - 如果不调用
start(),线程将一直保持NEW状态。
- 调用线程对象的
- 特点:在这个状态下,调用
run()方法是无效的,它不会开启新线程,而是直接在当前线程中执行run()方法的代码。
示例代码:
Thread myThread = new Thread(() -> {
System.out.println("Thread is running.");
});
System.out.println(myThread.getState()); // 输出: NEW
myThread.start(); // 启动线程
RUNNABLE (可运行状态)
- 描述:这是最复杂也最常用的状态,它表示线程已经准备好,并且正在运行中,或者正在等待操作系统分配 CPU 时间片,在 Java 6 之前,这个状态被称为 "Running",但为了更准确地反映现代操作线程调度机制(线程可能就绪但尚未真正运行),Java 6 将其更名为 "Runnable"。
- 如何进入:
- 从
NEW状态调用start()方法。 - 线程从
BLOCKED、WAITING或TIMED_WAITING状态转换回来。
- 从
- 如何转换:
- 当线程执行完
run()方法后,状态变为TERMINATED。 - 当线程需要获取锁但未能获取时,状态变为
BLOCKED。 - 当线程主动调用
wait(),join(),LockSupport.park()等方法时,状态变为WAITING或TIMED_WAITING。
- 当线程执行完
- 特点:
RUNNABLE状态涵盖了操作系统层面的 "就绪" 和 "运行" 两种情况,对于 Java 我们无法直接区分线程是正在运行还是在等待 CPU,这个转换由操作系统和 JVM 调度器完成。
示例代码:
Thread myThread = new Thread(() -> {
System.out.println("Thread is running. State: " + Thread.currentThread().getState());
});
myThread.start();
// 主线程稍后查看状态
try {
Thread.sleep(10); // 给新线程一点时间启动
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(myThread.getState()); // 输出: RUNNABLE (或 TERMINMINATED,如果执行太快)
BLOCKED (阻塞状态)
- 描述:线程因为等待一个监视器锁(monitor lock)而处于阻塞状态,换句话说,当一个线程试图进入一个被
synchronized修饰的代码块或方法时,如果锁正被其他线程持有,那么该线程就会进入BLOCKED状态。 - 如何进入:当线程尝试获取一个已经被其他线程占有的
synchronized锁时。 - 如何转换:
- 当其他线程释放了该锁,JVM 选择当前线程作为下一个获取锁的线程时,状态将变为
RUNNABLE。
- 当其他线程释放了该锁,JVM 选择当前线程作为下一个获取锁的线程时,状态将变为
- 特点:
BLOCKED状态是线程间竞争资源(锁)的直接体现,线程在BLOCKED状态时,不消耗 CPU 资源,只是被动等待。
示例代码:

final Object lock = new Object();
// 线程A
Thread threadA = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread A acquired the lock.");
try {
Thread.sleep(100); // 持锁一段时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread A released the lock.");
}
});
// 线程B
Thread threadB = new Thread(() -> {
System.out.println("Thread B is trying to acquire the lock...");
synchronized (lock) {
System.out.println("Thread B acquired the lock.");
}
});
threadA.start();
threadB.start();
try {
Thread.sleep(50); // 让线程A先拿到锁
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread B's state: " + threadB.getState()); // 输出: BLOCKED
WAITING (等待状态) 和 5. TIMED_WAITING (定时等待状态)
这两种状态都属于等待状态,但它们的唤醒方式不同。
WAITING (无限等待状态)
- 描述:线程等待另一个线程来执行一个特定的操作,这种等待是无限的,直到被其他线程唤醒。
- 如何进入:线程主动调用以下方法之一:
Object.wait()(无参数)Thread.join()(无参数)LockSupport.park()
- 如何转换:
- 被其他线程调用
Object.notify()或Object.notifyAll()唤醒后,状态变为RUNNABLE(但需要重新竞争锁)。 - 被
Thread.interrupt()中断后,会抛出InterruptedException,并退出等待状态。
- 被其他线程调用
- 特点:进入
WAITING状态的线程会释放其持有的锁(如果是通过wait()进入的)。
TIMED_WAITING (定时等待状态)
- 描述:与
WAITING类似,但它是在一个指定的时间段内等待,超时后,线程会自动被唤醒。 - 如何进入:线程主动调用带有超时参数的方法之一:
Thread.sleep(long milliseconds)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(long nanos)LockSupport.parkUntil(long deadline)
- 如何转换:
- 指定的等待时间到期,状态变为
RUNNABLE。 - 在等待期间被其他线程唤醒(
notify()/notifyAll()),状态变为RUNNABLE。 - 在等待期间被
Thread.interrupt()中断,抛出InterruptedException,并退出等待状态。
- 指定的等待时间到期,状态变为
- 特点:
sleep()是一个静态方法,它让当前线程休眠,并且不会释放任何锁,而wait()会释放锁。
示例代码:
final Object lock = new Object();
Thread waitingThread = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Waiting thread is waiting...");
// 进入 TIMED_WAITING 状态
lock.wait(2000);
System.out.println("Waiting thread woke up.");
} catch (InterruptedException e) {
System.out.println("Waiting thread was interrupted.");
}
}
});
waitingThread.start();
try {
Thread.sleep(1000); // 主线程等待1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Waiting thread state after 1s: " + waitingThread.getState()); // 输出: TIMED_WAITING
// 唤醒等待的线程
synchronized (lock) {
lock.notify(); // 或者不调用,让它自动超时
}
try {
waitingThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Waiting thread state at the end: " + waitingThread.getState()); // 输出: TERMINATED
TERMINATED (终止状态)
- 描述:线程的
run()方法已经执行完毕,或者因为未捕获的异常而终止,线程的生命周期结束。 - 如何进入:
- 线程的
run()方法正常执行完毕。 - 线程的
run()方法抛出了一个未捕获的异常。
- 线程的
- 如何转换:一旦进入
TERMINATED状态,线程就不可再被启动,调用start()方法会抛出IllegalStateException。 - 特点:
TERMINATED状态的线程对象仍然可以被引用,但其内部的生命周期已经结束。
状态转换图
为了更直观地理解,我们可以用一个状态转换图来表示:
graph TD
A[NEW] -->|start()| B[RUNNABLE];
B -->|run()方法结束| F[TERMINATED];
B -->|获取synchronized锁失败| C[BLOCKED];
C -->|成功获取锁| B;
B -->|调用wait(), join(), park()| D[WAITING];
B -->|调用sleep(), wait(timeout), join(timeout)| E[TIMED_WAITING];
D -->|被notify()/notifyAll()中断| B;
E -->|超时/被唤醒| B;
D -->|被interrupt()中断| B;
E -->|被interrupt()中断| B;
C -->|被interrupt()中断| B; // 注意:中断一个BLOCKED的线程会将其状态变为RUNNABLE,并抛出InterruptedException
总结与关键点
RUNNABLE是核心:它涵盖了“就绪”和“运行”,是线程工作的主要状态。BLOCKEDvsWAITING:BLOCKED是被动的,因为竞争锁而无法运行。WAITING/TIMED_WAITING是主动的,因为调用了wait(),sleep()等方法而暂停。
- 锁的释放:
- 在
BLOCKED状态下,线程不持有锁,只是在等待锁。 - 在
WAITING状态下(由wait()导致),线程会释放其持有的锁。 - 在
TIMED_WAITING状态下(由sleep()导致),线程不会释放任何锁。
- 在
- 查看状态:可以通过
Thread.getState()方法在任何时候获取线程的当前状态,这对于调试非常有用。
掌握这些状态及其转换,是进行高效、健壮的多线程编程的必备知识。

