虚拟线程整理

一、 核心概念与底层原理

1. 什么是虚拟线程?

虚拟线程是 JDK 21 正式引入的轻量级并发原语。它不是操作系统级别的线程,而是由 JVM 在用户态管理的极轻量级对象。其核心目标是以极低的成本支持超高并发,彻底解决传统线程模型在 I/O 密集型场景下的瓶颈。

2. M:N 调度模型
  • 传统模型 (1:1):一个 Java 线程(Platform Thread)对应一个操作系统线程。OS 线程的创建、销毁和上下文切换成本极高(通常占用 1MB 内存),导致并发上限通常在几千左右。
  • 虚拟线程 (M:N):M 个虚拟线程复用 N 个载体线程(Carrier Thread)。载体线程的数量通常等于 CPU 核心数。虚拟线程极其轻量,创建百万级虚拟线程毫无压力。
3. 核心运行机制:挂载与卸载 (Mount/Unmount)

虚拟线程的调度不依赖操作系统的抢占式调度,而是基于协作式调度

  • 挂载 (Mount):虚拟线程被绑定到一个载体线程上,此时它真正占用了 CPU 核心执行代码。
  • 卸载 (Unmount) :当虚拟线程执行到阻塞操作(如 I/O 读写、LockSupport.park()Thread.sleep())时,JVM 会自动将其从载体线程上"摘除"。
  • 恢复 (Remount):阻塞操作完成后,JVM 会自动将其重新挂载到某个空闲的载体线程上继续执行。
4. 调度器:ForkJoinPool 与 Work-Stealing
  • 虚拟线程默认运行在一个全局的 ForkJoinPool 中。
  • 工作窃取 (Work-Stealing):当某个载体线程的本地队列为空时,它会主动从其他繁忙的载体线程队列中"偷"任务来执行,从而最大化 CPU 利用率,避免线程饥饿。

二、 为什么需要虚拟线程?(对比分析)

表格

维度 传统平台线程 (Platform Thread) 协程/手动让出 (如 Kotlin Coroutines) 虚拟线程 (Virtual Threads)
内存开销 极高(~1MB/线程) 极低(几KB) 极低(初始仅几百字节)
并发上限 数千 数十万 数百万
编程范式 同步阻塞代码 异步/挂起函数(需学习新语法) 纯同步阻塞代码
阻塞处理 阻塞 OS 线程,浪费 CPU 需手动标记 suspend 关键字 自动检测并让出载体
生态兼容 完美 需特定框架支持 完美兼容现有 JDK API

核心优势总结 :虚拟线程让开发者用写传统同步阻塞代码的方式,获得媲美异步非阻塞(Reactive)的高并发性能


三、 最佳实践与使用方式

1. 创建与执行
复制代码
// 方式 1:直接启动(适用于少量临时任务)
Thread.startVirtualThread(() -> {
    System.out.println("Hello Virtual Thread!");
});

// 方式 2:使用 ExecutorService(强烈推荐,便于资源管理和优雅关闭)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 100_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1)); // 阻塞时自动让出载体
            return i;
        });
    });
} // try-with-resources 会自动等待所有任务完成并关闭
2. 核心使用原则(⚠️ 避坑指南)
  • 不要池化虚拟线程 :虚拟线程是"用完即弃"的消耗品,创建和销毁成本极低。永远不要使用固定大小的线程池来运行虚拟线程,应使用 newVirtualThreadPerTaskExecutor(),让每个任务独占一个虚拟线程。
  • 仅适用于 I/O 密集型任务:虚拟线程的优势在于处理高并发 I/O(网络请求、数据库查询、文件读写)。对于 CPU 密集型任务,虚拟线程没有性能优势,甚至可能因为上下文切换带来额外开销。
  • 避免长时间 Pinning(固定) :如果在 synchronized 块或 native 方法中发生阻塞,虚拟线程无法卸载,会连带把载体线程一起阻塞。应尽量使用 ReentrantLock 替代 synchronized

四、 适用场景与局限性

绝佳适用场景
  • 高并发微服务网关:处理海量 HTTP 请求。
  • 数据聚合服务:同时调用数十个下游微服务并等待结果。
  • 爬虫与批量数据处理:高并发的网络 I/O 操作。
  • 传统遗留系统改造:无需重构为 WebFlux/RxJava,只需升级 JDK 并替换线程池,即可获得数倍的吞吐量提升。
不适用场景
  • 纯 CPU 密集型计算:如视频编解码、复杂数学运算(应使用传统线程池或并行流)。
  • 强依赖底层 OS 线程绑定的场景:如某些需要绑定特定 CPU 核心的底层系统编程。
相关推荐
白露与泡影2 小时前
2026秋招冲刺:1000道Java高频面试题(各大厂考点汇总)
java·开发语言·面试
IT龟苓膏2 小时前
Java 并发基础:进程、线程、线程状态、synchronized、volatile 一篇讲清
java·开发语言·jvm
weixin_446729162 小时前
java中class类没有打进war包中
java
哭哭啼2 小时前
pgSql 事务篇
java·数据库·postgresql
架构源启2 小时前
Spring AI进阶系列(17)- 未来展望与职业发展:Java 工程师迈向 AI 工程化与智能体架构的路线图
java·人工智能·spring
我登哥MVP2 小时前
Spring Boot 从“会用”到“精通”:SpringBoot MVC 请求处理全流程
java·spring boot·后端·spring·mvc·maven·intellij-idea
我登哥MVP2 小时前
Spring Boot 从“会用”到“精通”:ReturnValueHandler原理
java·spring boot·后端·spring·java-ee·maven·intellij-idea
snow@li2 小时前
数据库:MySQL vs PostgreSQL 详尽对比(2026版)
java·mysql·postgresql
丑过三八线3 小时前
Runc 深度解析:从原理到实操
java·linux·开发语言·docker·容器·rpc