前言
本文主要介绍Java线程的六种线程状态、线程状态之间的流转和Java中的线程中断机制。
Java线程不是简单的代码执行单元,而是有着完整生命周期的复杂对象。它从诞生(NEW)到死亡(TERMINATED),其间经历了RUNNABLE的活跃、BLOCKED的等待、WAITING的休眠等多种状态。每个状态的转换都遵循着严格的规则,理解这些规则不仅有助于我们编写正确的并发代码,更能让我们在调试时准确定位问题所在。
而Java提供的中断机制是一种精巧的协作式控制手段——它不是粗暴的“杀戮命令”,而是一种优雅的“请求信号”。线程可以选择响应这个信号,清理资源后从容退出;也可以选择忽略它,继续自己的使命。这种设计哲学体现了Java在并发控制上的深思熟虑:将控制的主动权交给线程自身。
1. Java线程状态
Java 线程有 6 种状态,定义在 java.lang.Thread.State 枚举中:
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
状态总览表:
| 状态 | 枚举值 | 触发条件 | 备注 |
|---|---|---|---|
| NEW 新建 | Thread.State.NEW | new Thread() 后,start() 前 | 线程对象已创建,但尚未启动 |
| RUNNABLE 可运行 | Thread.State.RUNNABLE | 调用 start() 方法后 | 包含操作系统中的"就绪"和"运行"两种状态 |
| BLOCKED 阻塞 | Thread.State.BLOCKED | 等待进入 synchronized 代码块/方法 | 仅针对 synchronized,Lock接口不会进入此状态 |
| WAITING 无限等待 | Thread.State.WAITING | 调用以下方法: • Object.wait()• Thread.join()• LockSupport.park() | 无超时时间的等待 |
| TIMED_WAITING 超时等待 | Thread.State.TIMED_WAITING | 调用以下方法: • Thread.sleep(ms)• Object.wait(timeout)• Thread.join(timeout)• LockSupport.parkNanos()• LockSupport.parkUntil() | 有超时时间的等待 |
| TERMINATED 终止 | Thread.State.TERMINATED | run() 方法执行结束或异常退出 | 线程生命周期结束 |
代码示例:状态查看
public class ThreadStateDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
System.out.println("线程启动后状态: " + Thread.currentThread().getState()); // RUNNABLE
Thread.sleep(1000); // 进入 TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("创建后状态: " + t.getState()); // NEW
t.start();
Thread.sleep(100); // 让线程启动
System.out.println("启动后状态: " + t.getState()); // TIMED_WAITING (sleeping)
t.join();
System.out.println("结束后状态: " + t.getState()); // TERMINATED
}
}
2. 线程状态流转
graph TD
A[NEW<br>新建] -->|调用 start| B[RUNNABLE<br>可运行]
B -->|获取CPU时间片| C[RUNNING<br>实际运行中]
C -->|时间片用完| B
B -->|等待IO/资源| D[WAITING/TIMED_WAITING<br>等待/超时等待]
D -->|被通知/超时| B
B -->|等待synchronized锁| E[BLOCKED<br>阻塞]
E -->|获取锁| B
B -->|run方法结束| F[TERMINATED<br>终止]
C -.->|Java状态机制中<br>RUNNABLE已包含运行状态| B
状态转换触发条件表
| 转换方向 | 触发条件 | 方法调用示例 |
|---|---|---|
| NEW → RUNNABLE | 启动线程 | thread.start() |
| RUNNABLE → BLOCKED | 竞争 synchronized 锁失败 | synchronized(obj) { ... } |
| BLOCKED → RUNNABLE | 获取到 synchronized 锁 | 锁被释放后竞争成功 |
| RUNNABLE → WAITING | 无限期等待 | obj.wait()、thread.join() |
| WAITING → RUNNABLE | 被通知/中断 | obj.notify()、thread.interrupt() |
| RUNNABLE → TIMED_WAITING | 有限期等待 | Thread.sleep(1000)、obj.wait(1000) |
| TIMED_WAITING → RUNNABLE | 超时/被通知/中断 | 超时结束、obj.notify()、thread.interrupt() |
| RUNNABLE → TERMINATED | 线程执行完毕 | run() 方法正常结束或抛出未捕获异常 |
3. Java线程中断
Java 中断核心: 简单来说,中断就是临时打断线程的工作。在Java线程里面, 中断是协作式的,不是强制终止。Java线程受到中断只是设置一个中断标志位,不会立即停止线程,线程自己决定如何响应中断。
中断相关的核心三个方法如下:
// 1. 中断线程(设置中断标志)
public void interrupt() {
// 如果线程在 WAITING/TIMED_WAITING 状态,会抛出 InterruptedException
// 并清除中断标志
}
// 2. 检查中断标志(不清除)
public boolean isInterrupted() {
return interruptFlag; // 只是检查,不修改
}
// 3. 检查并清除中断标志(静态方法)
public static boolean interrupted() {
boolean flag = currentThread().interruptFlag;
if (flag) {
currentThread().interruptFlag = false; // 清除标志
}
return flag;
}
中断对不同状态的影响:
| 线程状态 | interrupt() 效果 | 中断标志位 |
|---|---|---|
| NEW | 无效果 | 保持 false |
| RUNNABLE | 仅设置标志位 | true |
| BLOCKED | 仅设置标志位 | true |
| WAITING | 抛出 InterruptedException | 清除为 false |
| TIMED_WAITING | 抛出 InterruptedException | 清除为 false |
代码示例:
public class DifferentStateInterruptDemo {
public static void main(String[] args) {
// 专门用于 WAITING 示例的锁对象,避免与 BLOCKED 示例竞争同一把锁
final Object waitLock = new Object();
// 1. RUNNABLE 状态的中断
Thread runnableThread = new Thread(() -> {
long sum = 0;
while (!Thread.currentThread().isInterrupted()) {
sum++; // 纯CPU计算,不会自动检查中断
}
System.out.println("计算线程收到中断,sum=" + sum);
});
// 2. WAITING 状态的中断
Thread waitingThread = new Thread(() -> {
synchronized (waitLock) {
try {
waitLock.wait(); // WAITING 状态
} catch (InterruptedException e) {
System.out.println("等待线程被中断");
}
}
});
// 3. TIMED_WAITING 状态的中断
Thread sleepingThread = new Thread(() -> {
try {
Thread.sleep(10000); // TIMED_WAITING状态
} catch (InterruptedException e) {
System.out.println("睡眠线程被中断");
}
});
// 4. BLOCKED 状态的中断
Thread blockedThread = new Thread(() -> {
System.out.println("blockedThread: 准备获取类锁...");
synchronized (DifferentStateInterruptDemo.class) {
System.out.println("blockedThread: 获取到类锁,isInterrupted="
+ Thread.currentThread().isInterrupted());
}
System.out.println("blockedThread: 运行结束");
});
// 启动线程
runnableThread.start();
waitingThread.start();
sleepingThread.start();
// 先让主线程持有类锁,再启动 blockedThread,使其进入 BLOCKED 状态
synchronized (DifferentStateInterruptDemo.class) {
blockedThread.start();
try {
// 短暂休眠,确保 blockedThread 已经因为竞争锁进入 BLOCKED 状态
Thread.sleep(100);
} catch (InterruptedException e) {
// 恢复中断标记,交给后续逻辑决定是否继续
Thread.currentThread().interrupt();
}
System.out.println("blockedThread 当前状态: " + blockedThread.getState());
// 在 BLOCKED 状态下对其调用 interrupt()
blockedThread.interrupt();
try {
// 短暂休眠,确保 blockedThread 已经受到interrupt影响
Thread.sleep(100);
} catch (InterruptedException e) {
// 恢复中断标记,交给后续逻辑决定是否继续
Thread.currentThread().interrupt();
}
System.out.println("主线程在 BLOCKED 状态下中断 blockedThread");
}
// 中断所有线程
runnableThread.interrupt();
waitingThread.interrupt();
sleepingThread.interrupt();
// 对 blockedThread 而言,刚才的 interrupt() 只是在其仍然 BLOCKED 时设置了中断标记,
// 等它真正拿到锁并继续执行时,通过 isInterrupted() 可以观察到这一点。
try {
blockedThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("blockedThread 最终状态: " + blockedThread.getState());
}
}
运行结果:
blockedThread: 准备获取类锁...
blockedThread 当前状态: BLOCKED
主线程在 BLOCKED 状态下中断 blockedThread
睡眠线程被中断
等待线程被中断
计算线程收到中断,sum=385188478
blockedThread: 获取到类锁,isInterrupted=true
blockedThread: 运行结束
blockedThread 最终状态: TERMINATED