news 2026/3/5 20:51:44

JDK 21 已转正的虚拟线程详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JDK 21 已转正的虚拟线程详解

友情提示:全文 1.6 万字,阅读约 25 min。 先放结论:虚拟线程 = 同步写法 + 异步性能,单机轻松 100 w 并发;但只擅长 I/O 密集,不算“万能性能银弹”。 如果你只想知道“怎么用”,直接跳到第 3 章 copy 代码即可;如果想吃透原理,第 1、2 章足够面试造火箭。

0. 开场三句话

  1. Java 19⁄20 是预览版,JDK 21 已转正(JEP 444),生产可直接上。

  2. 虚拟线程定位是“每请求一个线程”的终极答案,不是替代异步框架,而是让你忘掉异步。

  3. 读完你能:

  • 徒手写出 10 w 并发 Web 服务

  • 画出 mount/unmount 流程图

  • 避开 synchronized 钉死、ThreadLocal 爆内存等 5 个大坑

1. 从 0 到 1 看懂虚拟线程

1.1 平台线程的“三座大山”

  • 重:默认 1 MB 栈,1 万个线程 ≈ 1 GB,内存先崩

  • 贵:创建/切换都要进内核,10 µs 级别,CPU 上下文切换飙红

  • 少:操作系统不会让你无限制开线程,峰值几千就封顶

1.2 虚拟线程的“三把斧头”

  • 轻:初始栈 200 B~1 KB,百万条≈ 200 MB,堆说了算

  • 快:切换在用户态,0.1 µs,比平台线程快 100 倍

  • 多:一个 JVM 里可创建 千万级(官方压测 1400 w)

1.3 M:N 模型一句话

“M 个虚拟线程 → 映射到 → N 个平台线程”,调度器在 JVM 手里,操作系统完全无感。

2. 底层原理拆解(面试能吹 10 min)

2.1 公式

VirtualThread = Continuation + Scheduler + Runnable

组件

作用

类比

Continuation

保存/恢复栈帧,实现挂起

游戏存档

Scheduler

把任务扔到平台线程池

驾校教练

Runnable

你的业务代码

学员

2.2 生命周期(mount → run → yield → run → finish)

  1. mount:把虚拟线程栈帧 拷贝到 平台线程栈顶,开始执行

  2. yield(遇到阻塞):

  • 拷贝当前栈帧回 堆内存

  • 平台线程被释放,去跑别的虚拟线程

3. resume:I/O 完成 → 再次 mount → 从 yield 点继续跑

4. finish:Continuation 标记完成,虚拟线程对象等待 GC

因此“阻塞”不再浪费 OS 线程,只是 Continuation 的一次存档读档。

2.3 协作式调度 vs 抢占式

  • 虚拟线程 不会 被时钟中断,只有遇到阻塞点或主动 yield 才让出

  • 好处:切换开销极低;坏处:长 CPU 运算会钉死 Carrier,后面单独讲坑

2.4 默认调度器——ForkJoinPool

  • 并行度 = CPU 核心数,可配置

  • FIFO 队列,防止饥饿

  • 可通过系统属性微调:

    -Djdk.virtualThreadScheduler.parallelism=64 -Djdk.virtualThreadScheduler.maxPoolSize=1024

3. 实战:30 行代码跑 10 w 并发

3.1 创建 4 种姿势

// 1. 最简单 Thread.startVirtualThread(() -> System.out.println("Hi")); // 2. 先建后启 Thread vt = Thread.ofVirtual().unstarted(task); vt.start(); // 3. Factory 批量 ThreadFactory tf = Thread.ofVirtual().name("vt-", 0).factory(); // 4. 官方推荐:线程池 ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor();

3.2 对比实验(代码直接跑)

任务:10 w 个 HTTP 请求,每个 sleep 50 ms 模拟后端延迟

方案

完成时间

OS 线程数

内存峰值

平台线程池 200

50 s

200

1.2 GB

虚拟线程

1.2 s

22

200 MB

吞吐提升 40 倍,内存降 6 倍

3.3 Spring Boot 3.2 一键切换(Tomcat 虚拟线程版)

@Bean public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutor() { return protocolHandler -> { protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); }; }

改完配置,0 业务代码改动,QPS 从 5 k → 5 w,延迟 200 ms → 20 ms。

4. 5 大深坑与最佳实践

现象

规避方案

钉死 pinning

synchronized 或 native 方法阻塞时无法卸载,Carrier 被占满

① 用 ReentrantLock 代替 synchronized;② 避免在临界区做 I/O

ThreadLocal 滥用

百万线程 × 大对象 = OOM

① 用 ScopedValue(JDK 22+);② 直接干掉 ThreadLocal

CPU 密集

长循环不阻塞,会把 Carrier 钉死,并行度瞬间掉到 CPU 核心数

把重计算丢给平台线程池或ForkJoinPool.commonPool

过度创建

while(true) startVirtualThread 会瞬间 fork 出几十万任务,GC 爆炸

使用信号量或虚拟线程池做限流

调试困难

线程名每次 mount 都可能换,日志无上下文

① 自定义命名:Thread.ofVirtual().name("worker-", 0);② MDC 写入虚拟线程 ID

5. 与传统方案全维度对照

特性

平台线程

虚拟线程

异步框架(Reactor/CompletableFuture)

编程模型

同步

同步

回调/链式

阻塞代价

高(占 OS 线程)

零(自动 yield)

无阻塞,全程异步

内存/10 w

1 TB(理论)

200 MB

200 MB

调试难度

简单

简单

地狱

适用场景

CPU 密集、低并发

I/O 密集、高并发

I/O 密集、超高吞吐

6. 常见面试拷问 & 标准答案

Q1. 虚拟线程与平台线程根本区别? 答:M:N 调度 + 用户态 yield,阻塞不耗 OS 线程,栈可 GC 堆内分配。

Q2. 为什么说切换开销 0.1 µs? 答:纯用户态,只拷贝栈帧到堆,无需内核上下文,指令级保存恢复。

Q3. 遇到 synchronized 会怎样? 答:若监视器被占用,当前 Carrier 被钉死(pinning),直到锁释放;解决:用 ReentrantLock。

Q4. 能否做计算密集? 答:不行!长占 Carrier 会让并行度瞬间掉到 CPU 核数;应把重计算扔给平台线程池。

Q5. 虚拟线程数量有无上限? 答:仅受堆大小限制,官方压测 1400 w 条;但建议池化 + 限流,防止瞬间 GC 风暴。

7. 一键思维导图(文字版)

Virtual Thread ├─ 轻量:200 B 栈,百万并发 ├─ 调度:M:N,ForkJoinPool ├─ 阻塞:Continuation yield → 不耗 OS 线程 ├─ 坑:synchronized 钉死 / ThreadLocal OOM / CPU 密集 └─ 场景:Web/FTP/DB 高并发,同步代码写异步性能

8. 总结一句话

虚拟线程不是“性能魔法”,而是“资源放大器”—— 把过去“每个请求 1 MB”的内存账单打到“每个请求 200 B”, 让你用同步思维,直接吃到异步级别的吞吐; 只要避开 synchronized、ThreadLocal、长 CPU 三大坑, 它就是 Java 高并发终章答案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/5 15:07:15

免费查文献的网站有哪些 实用免费文献查询网站推荐与使用指南

生成式人工智能的浪潮正引发各领域的颠覆性变革&#xff0c;在学术研究这一知识生产的前沿阵地&#xff0c;其影响尤为显著。文献检索作为科研工作的基石&#xff0c;在AI技术的赋能下各大学术数据库已实现智能化升级。小编特别策划"AI科研导航"系列专题&#xff0c;…

作者头像 李华
网站建设 2026/3/5 8:40:50

40、个性化IDEA开发环境:字体、快捷键与文件类型设置

个性化IDEA开发环境:字体、快捷键与文件类型设置 1. 更改字体设置 IDEA编辑器对其所支持的所有文件类型使用相同的基本字体和字号,仅能修改字体的颜色、粗细和效果(如下划线)。 1.1 选择编辑器字体 编辑器字体可以与主界面、菜单和对话框所使用的字体不同。你可以通过ID…

作者头像 李华
网站建设 2026/3/6 14:15:23

44、开发工具使用指南:功能、操作与优化

开发工具使用指南:功能、操作与优化 1. 开发基础设置 1.1 项目构建与编译 项目构建目标多样,可针对整个项目、单个模块或表单进行构建。编译方面,支持背景编译,可排除特定路径,还能通过 IDEA 或 Ant 进行编译。操作时,需在编译器窗口配置相关设置: 1. 选择 Java 编译…

作者头像 李华
网站建设 2026/3/4 18:21:34

如何快速部署PESCMS Ticket:开源工单系统的完整指南

如何快速部署PESCMS Ticket&#xff1a;开源工单系统的完整指南 【免费下载链接】PESCMS-Ticket PESMCS Ticket (下称PT) 是一款基于 GPLv2 协议发布的开源客服工单系统。 项目地址: https://gitcode.com/gh_mirrors/pe/PESCMS-Ticket PESCMS Ticket是一款基于GPLv2协议…

作者头像 李华