一、虚拟线程 VS 原始线程:核心区别
|
特性 |
原始线程(Platform Thread) |
虚拟线程(Virtual Thread) |
|
创建方式 |
new Thread() / 线程池 |
Thread.ofVirtual().start() |
|
底层实现 |
每个线程绑定一个操作系统线程 |
多个虚拟线程复用少量操作系统线程 |
|
内存开销 |
每个线程约 1MB 栈空间 |
几 KB,按需增长 |
|
创建成本 |
高,数量受限 |
极低,可创建百万级线程 |
|
阻塞行为 |
阻塞会占用系统资源 |
阻塞时自动挂起,不占用底层线程 |
|
调度方式 |
操作系统调度 |
JVM 用户态调度(如 ForkJoinPool) |
简而言之:虚拟线程是“轻量版”的线程,能让你写出同步风格的代码,却拥有异步的性能。
二、虚拟线程能完全取代原始线程吗?
虚拟线程适合:
- 高并发、I/O 密集型任务(如 Web 请求、数据库访问)
- 使用阻塞式 API 的老项目迁移
- 快速开发同步风格的并发代码
不适合虚拟线程的场景:
- CPU 密集型任务(如图像处理、复杂计算)
- 依赖异步框架(如 Netty、Reactor)的应用
- 对线程调度有严格控制需求的底层系统
原始线程适合:
- 需要精细控制线程生命周期的场景
- CPU 密集型任务
- 与底层系统线程强绑定的任务
三、代码示例:传统线程 vs 虚拟线程
原始线程写法:
new Thread(() -> {
System.out.println("Platform thread: " + Thread.currentThread());
}).start();
虚拟线程写法(JDK 21+):
Thread.startVirtualThread(() -> {
System.out.println("Virtual thread: " + Thread.currentThread());
});
批量创建虚拟线程(高并发场景):
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10000; i++) {
int id = i;
executor.submit(() -> {
System.out.println("Task " + id + " running in " + Thread.currentThread());
});
}
executor.shutdown();
你可以轻松创建上万个虚拟线程而不会耗尽资源,这在传统线程中几乎不可能。
四、虚拟线程可以无限创建吗?
理论上接近无限,但实际上仍有限制。
- 虚拟线程是由 JVM 管理的轻量级线程,不绑定操作系统线程,因此创建成本极低(约 0.015ms/线程)。
- 实测中,在 32 核 CPU + 64GB 内存的环境下,成功创建了超过 100 万个虚拟线程。
- 但 JVM 依旧需要为每个虚拟线程分配栈空间(初始几 KB),所以受限于 内存总量 和 JVM 参数配置(如 -Xss 栈大小)。
结论:不是无限,但远超传统线程的数量级,百万级并发是现实可达的。
五、创建数量跟 CPU 规格有关系吗?
有关系,但不是线性绑定。
- 虚拟线程采用 M:N 调度模型:多个虚拟线程(M)映射到少量平台线程(N)。
- JVM 会根据 CPU 核心数自动创建必定数量的“载体线程”(Carrier Threads)来执行虚拟线程任务。
- CPU 核心越多,调度效率越高,上下文切换成本越低,但虚拟线程的创建数量主要受 内存限制 而非 CPU 限制。
结论:CPU 核心数影响吞吐量和调度效率,但不直接限制虚拟线程数量。
拟线程会随着 线程数量的增加 性能降低吗
俊赟,这几个问题问得超级到位,都是虚拟线程落地前必须搞清楚的关键点。下面我来逐一拆解,并结合实测数据和底层原理,给你一个清晰的答案。
六、虚拟线程数量增加后性能会下降吗?
是的,但下降曲线远优于传统线程。
- 当虚拟线程数量达到几十万甚至百万级时:
- JVM 的调度器负担加重
- GC 压力上升
- 栈空间占用变大
- 百万虚拟线程处理 HTTP 请求时,响应时间仍优于传统线程池和 CompletableFuture 异步方案。
- 不过,如果任务是 CPU 密集型,虚拟线程无法提升性能,反而可能由于调度开销略有下降。
结论:性能的确 会随数量上升而下降,但下降幅度远小于传统线程,适合 I/O 密集型任务。
七、限流提议:如何控制虚拟线程并发量?
Semaphore semaphore = new Semaphore(100); // 限制最多100个并发任务
Runnable task = () -> {
try {
semaphore.acquire();
// 执行任务逻辑
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release();
}
};
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10000; i++) {
executor.submit(task);
}
总结一句话:
虚拟线程不是“无限线程”,但它让你在资源可控的范围内,轻松实现百万级并发。性能虽会下降,但远优于传统线程,尤其适合高并发、阻塞型任务。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END




















暂无评论内容