腾讯面试题:说一下什么是虚拟线程?底层原理知道吗?
在传统 Java 开发中,我们用的 Thread 其实是直接映射到操作系统线程的,每创建一个 Thread,操作系统就会分配一个内核级别的线程,这种模式虽然简单,但也有个致命缺点——太重了!线程上下文切换(Context Switch)成本高,线程调度开销大,在高并发场景下,创建大量线程会严重影响性能。
这时候,虚拟线程就登场了!
虚拟线程并不是直接映射到 OS 线程的,而是由 JVM 自己实现的“轻量级线程”,多个虚拟线程可以共享一个 OS 线程(也就是我们常说的平台线程),JVM 会智能地调度它们,避免大量线程创建带来的开销。
简单理解就是,传统 Thread 是“每个 Java 线程对应一个 OS 线程”,而虚拟线程是“多个 Java 线程复用少量 OS 线程”,这样就能让 Java 在处理超高并发任务时更加高效。
那么,它的优势到底体现在哪?
首先是轻量,创建一个虚拟线程的成本几乎可以忽略不计,官方测试能在 1GB 内存里创建百万级别的线程!这要是换成传统 Thread,早就把系统资源榨干了。
其次是让异步编程更简单。以前要写高性能代码,我们得用 CompletableFuture、Reactor 这些异步工具,代码复杂,调试也很头疼。
而有了虚拟线程,我们可以直接用同步写法,JVM 会帮我们处理并发任务,看起来像同步,实际是高并发,这就很舒服了!
当然,虚拟线程也不是万能的。它适合I/O 密集型任务,比如高并发 HTTP 请求、数据库访问等,但如果是 CPU 密集型任务(比如复杂计算、加密解密),虚拟线程就没什么优势,因为 CPU 资源是固定的,怎么分配都得等它跑完。
怎么用虚拟线程?
Java 19 开始,JDK 提供了好几种创建虚拟线程的方式,我们一个个来看看。
最简单的方式:
Thread.startVirtualThread(() -> {
System.out.println("Hello from Virtual Thread!");
});
或者用 Thread.ofVirtual() 创建:
Thread vt = Thread.ofVirtual().start(() -> {
System.out.println("Hello, Virtual Thread!");
});
还可以用 Executors.newVirtualThreadPerTaskExecutor() 创建虚拟线程池:
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println("Virtual thread: " + Thread.currentThread());
});
}
}
注意这里 try-with-resources 语法,ExecutorService 实现了 AutoCloseable,在 try 结束时会自动关闭线程池。
那么,虚拟线程到底比传统线程快多少?
来看一个对比实验,假设我们要创建 10000 个任务,每个任务执行 0.5 秒。
如果用普通线程池(比如 Executors.newFixedThreadPool(200)):
ExecutorService executor = Executors.newFixedThreadPool(200);
for (int i = 0; i < 10000; i++) {
executor.submit(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
});
}
executor.shutdown();
这时候,任务执行时间大概是 25.6 秒,最大 OS 线程数 209 个(包含 JVM 后台线程)。
如果换成虚拟线程池(Executors.newVirtualThreadPerTaskExecutor()):
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10000; i++) {
executor.submit(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
});
}
executor.close();
任务执行时间直接降到 1.3 秒!最大 OS 线程数只有 22 个,说明虚拟线程极大减少了 OS 线程的开销。
这个实验充分证明了:在 I/O 密集型任务中,虚拟线程比传统线程高效太多了!
面试题:虚拟线程的底层原理是什么?
回答:
虚拟线程(Virtual Thread)是 JVM 级别的轻量级线程,它并不像传统的 Thread 那样直接映射到 OS 线程,而是由 JVM 调度执行。
JVM 通过载体线程(Carrier Thread) 执行虚拟线程,多个虚拟线程可以复用同一个载体线程。当虚拟线程遇到 I/O 阻塞时,JVM 会把它从载体线程上移除,避免 OS 线程空等,而让载体线程执行其他任务。这种机制称为协作式调度(Cooperative Scheduling),可以极大提高线程调度的效率。
底层实现主要依赖 ForkJoinPool,它会管理一组载体线程,并在其中调度虚拟线程。
简单来说,虚拟线程就是让 Java 线程摆脱了 OS 线程的束缚,使得高并发处理更加高效。适合 I/O 密集型任务,但对 CPU 密集型任务提升不大。
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。