连载中 20/21

虚拟线程:JDK 21 的并发新范式

2026-11-01 · 16 阅读 · 0 评论 · 0 赞

平台线程的天花板

前面二十篇的所有并发手段,都建立在平台线程上——它与操作系统线程 1:1 映射,创建、调度、上下文切换全是内核的活,一条线程默认约 1MB 栈内存。Web 服务「一请求一线程」的模型,在万级并发下只剩两条路:开一万条线程(内存与切换开销爆炸),或者线程池加异步改造(回调地狱、堆栈断裂、可读性崩塌)。瓶颈不在业务,在线程本身太贵。

虚拟线程:让阻塞变得便宜

虚拟线程由 JVM 调度,不直接映射 OS 线程。原理一句话:大量虚拟线程跑在少量载体线程上,某个虚拟线程阻塞时,JVM 把它的栈从载体线程上卸载到堆里,载体线程转身去跑别的虚拟线程;IO 就绪后再装载回来继续跑。阻塞的代价从「占住一条 OS 线程」变成「堆上多存一段栈」——便宜了三个数量级。服务端百万级虚拟线程,不再是新闻。

用法:几乎零成本切换

// 方式一:直接启动
Thread.startVirtualThread(() -> handle(request));

// 方式二:每任务一个虚拟线程的执行器
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> callRemoteApi());
}

注意哲学变化:虚拟线程不池化——它便宜到用完即弃,每任务新建一个才是推荐用法。newVirtualThreadPerTaskExecutor 返回的就是「不共享、不复用」的执行器,与第 14 篇的池化哲学正相反——不是线程池过时了,是「为省线程而池化」过时了,普通线程池依然是 CPU 密集任务的主力。

什么时候不该用

虚拟线程救的是 IO 密集:大量阻塞等待的调用。CPU 密集任务用它毫无收益——算力上限依然是核数。两个使用注意:一,不要给虚拟线程再套线程池,违背它的设计;二,早期版本里 synchronized 块内的阻塞会「钉住」(pinning)载体线程,导致栈无法卸载、阻塞退化成占线程——JDK 21 的应对是热点路径改用 ReentrantLock 或避开长阻塞,JDK 24 通过 JEP 491 已彻底修复,synchronized 不再钉住。

它改变了什么

最大的红利是代码形态:「一请求一线程」的同步阻塞写法可以回归——不必为了吞吐把代码改成回调迷宫。简单、线性、可读的阻塞代码,配上百万虚拟线程,这就是范式革命。CompletableFuture 依然是编排好手(组合、超时、异常链),但「为了性能被迫异步」的时代,开始翻篇了。

二十一篇的知识全部到位。下一篇收官:一张并发作战地图,把所有工具按「治哪宗罪、用在什么场景」串成一页纸。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Java#虚拟线程#JDK21#JUC#并发编程

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10113 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9876 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9306 阅读 · 21 评论 · 287 赞