虚拟线程(Virtual Threads)
传统线程的问题:每个线程占用 1MB 栈,创建/销毁成本高,线程数量受限于系统资源。
虚拟线程是 JDK 21 的核心特性,Project Loom 的成果。它不绑定 OS 线程,成本极低,可以创建数百万个。
与平台线程对比
| 对比项 | 平台线程 | 虚拟线程 |
|---|---|---|
| 栈大小 | 1MB | 按需扩展(~200-300字节) |
| 创建成本 | 高 | 极低 |
| 阻塞行为 | 阻塞 OS 线程 | 自动挂起 |
| 线程数量 | 数千 | 数百万 |
| 适用场景 | CPU 密集型 | IO 密集型 |
创建方式
方式一:Thread.ofVirtual()
java
Thread vt = Thread.ofVirtual().start(() -> {
System.out.println("Virtual Thread running");
});方式二:Executors.newVirtualThreadPerTaskExecutor()
java
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<?> future = executor.submit(() -> {
System.out.println("Virtual Thread task");
});
future.get();
}使用示例
HTTP 服务器
java
// 传统方式:线程池受限
ExecutorService executor = Executors.newFixedThreadPool(200);
// 虚拟线程方式:可以处理更多并发
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();数据库连接
java
// 虚拟线程方式:可以大量并发
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10000; i++) {
final int id = i;
executor.submit(() -> {
try (Connection conn = dataSource.getConnection()) {
// 每个虚拟线程可以独立获取连接
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
}
});
}
}虚拟线程特点
1. 自动释放阻塞资源
java
Thread.startVirtualThread(() -> {
Thread.sleep(1000); // 不会阻塞 OS 线程
});2. ThreadLocal 行为
java
ThreadLocal<String> tl = new ThreadLocal<>();
tl.set("value");
Thread.startVirtualThread(() -> {
System.out.println(tl.get()); // 可能为 null
});3. 不能使用 Thread.interrupt()
java
// ❌ 虚拟线程不支持中断
Thread virtualThread = Thread.ofVirtual().start(() -> {
Thread.sleep(10000);
});
virtualThread.interrupt(); // 无效!与现有代码兼容性
同步代码兼容
java
// 传统同步代码可以直接在虚拟线程中运行
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
try (Connection conn = dataSource.getConnection()) {
// ...
}
});
}框架兼容
| 框架 | 虚拟线程支持 |
|---|---|
| Spring Boot 3.2+ | ✅ 支持 |
| Jakarta EE 10+ | ✅ 支持 |
小结
虚拟线程是 JDK 21 的重要特性:
- 极低的内存占用和创建成本
- 可以创建数百万个虚拟线程
- 与现有代码高度兼容
- 推荐在 Web 服务、数据库访问等 IO 密集场景使用
