前言
Java 21 正式引入虚拟线程(Virtual Threads),这是 Project Loom 的核心成果。虚拟线程让 Java 并发编程从”难”变”简”,彻底改变了高并发应用的开发方式。本文带你全面掌握虚拟线程。
一、虚拟线程 vs 平台线程
- 平台线程:对应操作系统线程,创建成本高(约1MB栈内存),数量受限
- 虚拟线程:JVM 管理的轻量级线程,创建成本极低(约几KB),可创建数百万个
// 平台线程:创建100万个会OOM
Thread platformThread = new Thread(() -> doWork());
platformThread.start();
// 虚拟线程:创建100万个轻松搞定
Thread virtualThread = Thread.ofVirtual().start(() -> doWork());
二、创建虚拟线程的四种方式
// 方式1:Thread.ofVirtual()
Thread vt1 = Thread.ofVirtual().name("vt-1").start(() -> {
System.out.println("Virtual thread: " + Thread.currentThread());
});
// 方式2:Thread.startVirtualThread()
Thread vt2 = Thread.startVirtualThread(() -> {
System.out.println("Running in virtual thread");
});
// 方式3:虚拟线程 ExecutorService
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> processRequest());
executor.submit(() -> processRequest());
}
// 方式4:ThreadFactory
ThreadFactory factory = Thread.ofVirtual().factory();
Thread vt4 = factory.newThread(() -> doWork());
vt4.start();
三、实战:高并发 HTTP 请求处理
// 传统方式:线程池,受限于线程数
ExecutorService threadPool = Executors.newFixedThreadPool(200);
// 虚拟线程方式:每个请求一个虚拟线程
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// 虚拟线程会在 I/O 阻塞时自动挂起,释放载体线程
return userService.findById(id); // 数据库查询
}
}
// Spring Boot 3.2+ 开启虚拟线程
// application.yml
// spring:
// threads:
// virtual:
// enabled: true
四、性能对比测试
public class PerformanceTest {
// 模拟 I/O 密集型任务
static void ioTask() throws InterruptedException {
Thread.sleep(100); // 模拟数据库查询
}
public static void main(String[] args) throws Exception {
int taskCount = 10_000;
// 平台线程池
long start1 = System.currentTimeMillis();
try (ExecutorService pool = Executors.newFixedThreadPool(200)) {
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < taskCount; i++) {
futures.add(pool.submit(() -> { ioTask(); return null; }));
}
for (Future<?> f : futures) f.get();
}
System.out.println("Platform threads: " + (System.currentTimeMillis() - start1) + "ms");
// 输出约:5200ms
// 虚拟线程
long start2 = System.currentTimeMillis();
try (ExecutorService vExecutor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < taskCount; i++) {
futures.add(vExecutor.submit(() -> { ioTask(); return null; }));
}
for (Future<?> f : futures) f.get();
}
System.out.println("Virtual threads: " + (System.currentTimeMillis() - start2) + "ms");
// 输出约:120ms,提升40倍!
}
}
五、注意事项
- 避免 synchronized 块:会导致虚拟线程固定(pinning),改用 ReentrantLock
- 不适合 CPU 密集型任务:虚拟线程优势在 I/O 密集型场景
- ThreadLocal 谨慎使用:大量虚拟线程时内存占用可能增加
// 错误:synchronized 导致 pinning
synchronized (lock) {
Thread.sleep(100); // 虚拟线程被固定,无法挂起
}
// 正确:使用 ReentrantLock
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
Thread.sleep(100); // 虚拟线程可以正常挂起
} finally {
lock.unlock();
}
总结
虚拟线程是 Java 并发编程的重大突破,特别适合 I/O 密集型的微服务场景。升级到 Java 21 + Spring Boot 3.2,一行配置即可享受虚拟线程带来的性能提升。
觉得有帮助请点赞收藏!有问题欢迎评论区交流
文章摘自:https://www.cnblogs.com/czlws/p/19817808/java-virtual-threads-project-loom-concurrency
