忻州市网站建设_网站建设公司_网站备案_seo优化
2026/1/22 16:56:32 网站建设 项目流程

一、先给结论

虚拟线程不是不运行在 OS 线程上,而是:
只在“真正需要 CPU 时”才短暂占用 OS 线程。
在 IO 等待时,JVM 会把它“卸载”下来。


二、为什么传统线程一定占用 OS 线程?

1️⃣ Java 线程 = OS 线程(1:1)

在 Java 21 之前:

JavaThread<==>OSThread

当你写:

Threadt=newThread(()->httpCall());t.start();

本质是:

  • JVM 调用pthread_create
  • 创建一个真实的内核线程
  • 栈、调度、阻塞全交给操作系统

2️⃣ OS 不懂“这是 IO 等待”

当线程调用:

socket.read();

操作系统只知道一件事:

“这个线程现在在等数据”

于是:

  • OS 把线程状态设为BLOCKED
  • 线程仍然存在
  • 仍然占:
    • 内核线程结构
    • 栈内存
    • 调度成本

📌OS 无法把这个线程“拆掉”再给别人用


三、虚拟线程是如何“骗过”操作系统的?

关键思想:

👉阻塞不交给 OS,而是交给 JVM


1️⃣ 虚拟线程的真实结构

Virtual Thread(JVM对象) | |--- Continuation(可挂起的执行体) | |--- 运行在 ↓ Carrier Thread(少量 OS 线程)

Carrier Thread 才是真正的 OS 线程


2️⃣ JVM 在关键 IO 点“插手”了

虚拟线程的核心魔法在这里👇

传统线程:

Thread | |-- socket.read() | |-- OS 阻塞线程

虚拟线程:

VirtualThread | |-- socket.read() | |-- JVM 拦截 | |-- 保存当前执行现场(Continuation) |-- 从 Carrier Thread 上卸载 |-- 把 Carrier Thread 还给调度器

📌OS 完全不知道有这么回事


3️⃣ JVM 怎么知道“这是 IO”?

因为:

👉 JDK 的 IO 被“改造”了(关键)

以下 API 在虚拟线程下是可挂起的

  • Socket
  • HttpClient
  • InputStream / OutputStream
  • Selector
  • NIO

JDK 内部逻辑(简化):

if(currentThread.isVirtual()){parkContinuation();}else{blockOSThread();}

四、Continuation:真正的“黑科技”

1️⃣ 什么是 Continuation?

你可以理解为:

一个可以暂停 / 恢复的调用栈快照

它保存了:

  • 当前方法栈
  • 局部变量
  • 执行位置

2️⃣ 挂起时发生了什么?

┌──────────────┐ │ 方法 A │ │ 方法 B │ │ 方法 C <-- 当前执行点 └──────────────┘

JVM 做了:

  1. 把这段执行栈复制到堆内存
  2. 解绑当前 OS 线程
  3. 标记为 WAITING

3️⃣ 恢复时发生了什么?

当 IO 就绪:

  1. JVM 选一个空闲 Carrier Thread
  2. 把 Continuation 装回去
  3. 从 C 方法继续执行

👉就像什么都没发生过


五、为什么说“虚拟线程不占用 OS 线程”?

更准确的说法是:

**虚拟线程在“运行时”才占用 OS 线程
**在“等待时”不占用 OS 线程

对比:

状态传统线程虚拟线程
执行 CPU占 OS 线程占 OS 线程
等 IO仍占 OS 线程❌ 不占
空闲不占

六、这就是为什么并发能暴涨 100 倍

假设:

  • OS 线程池:200
  • IO 等待时间:95%

传统模型:

200 个线程 ≈ 190 个在等 IO ≈ 10 个在干活

虚拟线程模型:

200 个 Carrier Thread + 100,000 个 Virtual Thread ≈ 99,500 个在挂起 ≈ 500 个随时可运行

七、为什么你“几乎不用改代码”?

因为:

  • 同步 API 没变
  • try/catch 没变
  • ThreadLocal 可用
  • JDBC / HTTPClient 可用

JVM在你看不到的地方做了调度革命。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询