Java 21虚拟线程Virtual Threads原理与使用
请详细解释Java 21正式发布的虚拟线程(Virtual Threads,Project Loom)。虚拟线程与传统平台线程(OS线程)的区别是什么?如何使用虚拟线程?虚拟线程的底层调度原理(M:N模型、ForkJoinPool、Continuation)是什么?适用场景和注意事项有哪些?
回答
苦行僧
什么是虚拟线程
虚拟线程是JDK 21正式发布(JEP 444)的轻量级线程,由JVM管理而非操作系统。
- 平台线程(Platform Thread):映射到OS线程,创建、切换成本高
- 虚拟线程(Virtual Thread):数百万个虚拟线程复用到少量平台线程(M:N调度)
使用方法
// 方式1:Thread.ofVirtual()
Thread vThread = Thread.ofVirtual()
.name("vt-").start(() -> System.out.println("虚拟线程"));
// 方式2:Executors.newVirtualThreadPerTaskExecutor()
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> { /* 任务 */ });
}
// 方式3:Thread.startVirtualThread(Runnable)
Thread.startVirtualThread(() -> { ... });
底层原理
- Continuation:虚拟线程的核心是Continuation(协程),可暂停和恢复
- ForkJoinPool调度:虚拟线程挂载到ForkJoinPool的平台线程上运行
- 固定(Pinning):当虚拟线程执行synchronized块或native方法时,会被固定到平台线程(无法卸载)
- VThread Carrier线程:真正执行任务的平台线程,虚拟线程在park/unpark时切换
适用场景与注意事项
适用:
- 大量IO密集型任务(Web服务器、微服务、数据库调用)
- 每个请求一个线程的模型(如Tomcat)
- 高并发WebFlux的替代方案(用同步API达到响应式性能)
注意事项:
- 避免synchronized块中做阻塞操作(使用ReentrantLock替代)
- 避免线程池(虚拟线程本身已轻量,无需池化)
- ThreadLocal谨慎使用(虚拟线程数量多,ThreadLocal内存开销大)
- CPU密集型任务不适合(平台线程更合适)