卡塔尔世界杯_中国进过几次世界杯 - 210rc.com
首页世界杯波兰正文

【线程的几种状态】

2025-10-07 17:04:43

💡 摘要:你是否曾被 RUNNABLE 状态迷惑——它为何包含了“阻塞”?

是否在排查线程池时,看到 WAITING 状态却不知其因?

Java 线程的 6 种状态(NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED)

不仅是枚举值,更是理解 JVM 线程模型、锁竞争、协作机制的钥匙。

本文将从基础到深入,结合代码、图解、jstack 实战,

彻底讲清每种状态的含义、转换条件、监控方法与常见误区。

文末附高清状态转换图与面试高频问题清单,助你真正掌握多线程核心基础。

一、从“线程是什么”说起在深入状态前,先明确:线程是 CPU 调度的基本单位。

一个 Java 程序启动,JVM 会创建一个 main 线程。你可以创建更多线程,让任务并发执行。但 CPU 核心数有限,操作系统需要在多个线程间快速切换,造成“同时运行”的假象。 🔑 线程状态的本质:

描述线程在 JVM 和操作系统调度 下的当前所处阶段。

二、Java 线程状态全景Java 定义了 6 种线程状态,位于 java.lang.Thread.State 枚举中:

代码语言:javascript代码运行次数:0运行复制public enum State {

NEW, // 新建

RUNNABLE, // 可运行

BLOCKED, // 阻塞

WAITING, // 无限期等待

TIMED_WAITING, // 限期等待

TERMINATED // 终止

} ✅ 重要提示:

这是 JVM 层面的抽象状态,与操作系统的线程状态(如 running, ready, waiting)不完全等价。

特别是 RUNNABLE,它包含了操作系统的 ready(就绪)和 running(运行)两种状态。

三、逐个击破:6 种状态详解1. NEW(新建)——生命的起点含义:线程对象已创建,但尚未调用 start()。特点: 线程还未被 JVM 纳入调度。此时调用 getState() 可返回 NEW。代码语言:javascript代码运行次数:0运行复制Thread t = new Thread(() -> System.out.println("Hello"));

System.out.println(t.getState()); // 输出:NEW

t.start(); // 调用后,状态将改变 ✅ 生命周期的第一步。

2. RUNNABLE(可运行)——CPU 的“候选者”含义:线程正在 JVM 中执行,或正等待 CPU 分配时间片。关键理解(易错点!): RUNNABLE ≠ 正在运行!它包含两种 OS 状态: ready:已准备好,排队等 CPUrunning:正在 CPU 上执行I/O 阻塞(如读文件、网络请求)也属于 RUNNABLE!

因为 JVM 无法区分线程是在计算还是在等 I/O。代码语言:javascript代码运行次数:0运行复制// 示例 1:CPU 密集型(running)

Thread cpuTask = new Thread(() -> {

long sum = 0;

for (int i = 0; i < Integer.MAX_VALUE; i++) sum++;

}); // 状态:RUNNABLE

// 示例 2:I/O 操作(看似阻塞,但状态仍是 RUNNABLE)

Thread ioTask = new Thread(() -> {

try (FileInputStream fis = new FileInputStream("large.log")) {

fis.readAllBytes(); // I/O 阻塞中,但 getState() == RUNNABLE

} catch (IOException e) { e.printStackTrace(); }

}); 🔥 面试常考:为什么 I/O 阻塞的线程状态是 RUNNABLE?

答:JVM 的线程状态模型未细分 I/O 阻塞,只要线程未进入 wait/sleep/等锁,就视为“可运行”。

3. BLOCKED(阻塞)——锁的竞争者含义:线程试图获取一个监视器锁(monitor)失败,等待进入 synchronized 块/方法。触发场景: 尝试进入一个被其他线程持有的 synchronized 方法或代码块。从 WAITING 状态被唤醒后,重新竞争锁失败。代码语言:javascript代码运行次数:0运行复制Object lock = new Object();

Thread t1 = new Thread(() -> {

synchronized (lock) {

System.out.println("t1 持有锁,开始休眠...");

try { Thread.sleep(3000); } catch (InterruptedException e) {}

System.out.println("t1 释放锁");

}

});

Thread t2 = new Thread(() -> {

System.out.println("t2 尝试获取锁...");

synchronized (lock) { // t2 在此处进入 BLOCKED 状态

System.out.println("t2 终于获得锁!");

}

});

t1.start();

Thread.sleep(500);

t2.start(); // t2 会因锁被 t1 占有而进入 BLOCKED ✅ BLOCKED 的核心是 synchronized 锁的竞争。

4. WAITING(无限期等待)——协作的等待者含义:线程无限期等待另一个线程执行特定操作来唤醒它。进入方式(调用以下方法,无超时参数): Object.wait()Thread.join()(无超时)LockSupport.park()唤醒方式: Object.notify() / notifyAll()被其他线程中断(interrupt())LockSupport.unpark()代码语言:javascript代码运行次数:0运行复制Thread t1 = new Thread(() -> {

synchronized (lock) {

try {

System.out.println("t1 进入等待...");

lock.wait(); // t1 进入 WAITING 状态,释放锁

System.out.println("t1 被唤醒!");

} catch (InterruptedException e) { e.printStackTrace(); }

}

});

Thread t2 = new Thread(() -> {

synchronized (lock) {

System.out.println("t2 即将唤醒 t1");

lock.notify(); // 唤醒 t1

}

});

t1.start();

Thread.sleep(1000);

t2.start(); ✅ WAITING 状态的线程不消耗 CPU,是线程间协作的基础。

5. TIMED_WAITING(限期等待)——有耐心的等待者含义:线程等待一段时间,时间到后自动唤醒。进入方式(带超时参数): Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos(long nanos)唤醒方式: 超时自动唤醒被中断显式唤醒(如 notify)代码语言:javascript代码运行次数:0运行复制Thread t = new Thread(() -> {

try {

System.out.println("开始休眠 2 秒...");

Thread.sleep(2000); // 进入 TIMED_WAITING

System.out.println("休眠结束!");

} catch (InterruptedException e) { e.printStackTrace(); }

}); ✅ TIMED_WAITING 是 WAITING 的“限时版”。

6. TERMINATED(终止)——生命的终点含义:线程的 run() 方法已执行完毕,或因未捕获异常而退出。特点: 线程对象依然存在,但已“死亡”。无法再次 start()(会抛 IllegalThreadStateException)。代码语言:javascript代码运行次数:0运行复制Thread t = new Thread(() -> {

System.out.println("任务完成");

});

t.start();

t.join(); // 等待 t 结束

System.out.println(t.getState()); // 输出:TERMINATED四、线程状态转换图(高清版) ✅ 核心逻辑:

RUNNABLE 是中心枢纽。BLOCKED 专为 synchronized 锁设计。WAITING 和 TIMED_WAITING 用于线程协作。五、实战:如何监控线程状态?1. 代码中获取状态:getState()代码语言:javascript代码运行次数:0运行复制Thread t = new Thread(() -> {

try { Thread.sleep(1000); } catch (InterruptedException e) {}

});

System.out.println("NEW: " + t.getState());

t.start();

System.out.println("启动后: " + t.getState()); // 可能是 RUNNABLE

Thread.sleep(100);

System.out.println("休眠中: " + t.getState()); // TIMED_WAITING

t.join();

System.out.println("结束后: " + t.getState()); // TERMINATED ⚠️ 注意:getState() 是瞬时快照,可能不精确。

2. 生产环境利器:jstack代码语言:javascript代码运行次数:0运行复制# 1. 查找 Java 进程 ID

jps

# 2. 输出线程栈和状态

jstack 输出片段:

代码语言:javascript代码运行次数:0运行复制"main" #1 prio=5 os_prio=0 cpu=15.62ms elapsed=4.32s tid=0x000002aab8019000 nid=0x5a44 waiting on condition [0x000000b8c5fff000]

java.lang.Thread.State: TIMED_WAITING (sleeping)

at java.lang.Thread.sleep(java.base@17.0.8/Native Method)

at Main.main(Main.java:5) 🔥 jstack 是诊断死锁、性能瓶颈的必备工具。

3. 线程池中的状态线程池中的工作线程(worker)在空闲时会调用 workQueue.take(),进入 WAITING 状态,等待新任务。

六、常见问题与面试解析❓1. RUNNABLE 为什么包含 I/O 阻塞? 答:JVM 的线程状态模型是简化的。

只要线程没有调用 wait、sleep 或进入 synchronized 竞争锁,

即使它在等待 I/O,JVM 也认为它处于“可运行”状态。

这也是 jstack 中大量线程显示 RUNNABLE 的原因。

❓2. BLOCKED 和 WAITING 的本质区别? 答:

BLOCKED:因锁竞争失败而被动阻塞(synchronized)。WAITING:因主动协作而等待(wait/join),需其他线程显式唤醒。关键:WAITING 会释放锁,BLOCKED 不会。❓3. sleep() 和 wait() 的状态与锁行为? 答:

方法状态是否释放锁调用位置sleep()TIMED_WAITING否任意位置wait()WAITING是必须在 synchronized 块内

❓4. 线程终止后能重启吗? 答:不能。

线程是“一次性”的。终止后再次 start() 会抛 IllegalThreadStateException。

应使用线程池或创建新线程。

❓5. 如何判断线程是否活跃? 答:使用 thread.isAlive()。

当线程处于 RUNNABLE, BLOCKED, WAITING, TIMED_WAITING 时返回 true。

七、总结状态

触发条件

关键点

NEW

new Thread()

未启动

RUNNABLE

start() / I/O / 计算

包含就绪、运行、I/O 阻塞

BLOCKED

synchronized 竞争锁

锁竞争

WAITING

wait() / join() (无超时)

主动协作,需唤醒

TIMED_WAITING

sleep() / wait(timeout)

限期等待,自动唤醒

TERMINATED

run() 结束

生命周期结束

✅ 掌握线程状态,是理解并发编程的第一步。

动手实践,结合 jstack 分析,你将对多线程有更深的理解。

世界上人口最少的五个国家#涨知识 三国时期,魏蜀吴哪一个国家的实力最为强大
相关内容