JJava 知识库
JAVA INTERVIEW

高频面试题

Java多线程进阶约 3 分钟

如果把现有 Web 服务迁移到虚拟线程,你会先选哪些接口试点?还需要限制并发吗?

参考回答约 3 分钟 · 口语表达
先说结论

这个问题我会先说项目结论:虚拟线程是由 JVM 调度的轻量线程,允许大量阻塞式任务共享较少平台线程。它主要简化高并发 I/O 服务的线程成本和代码结构,不会让 CPU 计算突破核心数上限,也不能替代连接池、限流和背压。

01

我会先交代项目背景和选型结论。理解虚拟线程的轻量调度、阻塞式编程优势及固定线程和限流边界。虚拟线程是由 JVM 调度的轻量线程,允许大量阻塞式任务共享较少平台线程。它主要简化高并发 I/O 服务的线程成本和代码结构,不会让 CPU 计算突破核心数上限,也不能替代连接池、限流和背压。 阻塞操作能够挂起虚拟线程并释放载体线程时,平台线程可以继续运行其他任务,因此“一请求一线程”模型重新具有可扩展性。

02

具体落地时,我会沿着实际调用链来讲。沿着「创建海量虚拟线程 → 在载体线程上运行 → 遇到可挂起阻塞 → 卸载并释放载体 → I/O 就绪后重新调度」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 创建海量虚拟线程 虚拟线程由 JVM 管理,创建与栈内存成本远低于平台线程,适合一任务一线程模型。 在载体线程上运行 可运行虚拟线程挂载到有限 ForkJoinPool 载体线程执行,业务不应把载体数当成下游并发上限。 java.lang.VirtualThread:mount/unmount 与 continuation。 JFR VirtualThreadPinned:载体线程被固定事件。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。

03

参数和容量不能靠默认值,我会结合业务量来定。以 1万并发阻塞任务压测,分别限制/不限数据库许可;开启 jdk.tracePinnedThreads 或 JFR 检查 synchronized 内阻塞。

04

效果要用数据证明,线上问题也要能闭环。固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「虚拟线程数」为主基线,记录值应满足「可高但受内存预算」;同时保存 虚拟线程数量、载体线程利用率,使后续变化能够回到同一时间轴比较。 服务把固定 200 线程池替换为每请求虚拟线程,应用可同时发起数万 JDBC 查询,数据库连接池和排队迅速饱和。保留连接池与 Semaphore 并发许可后,虚拟线程只简化等待模型,不再绕过下游容量保护。 去掉并发上限压垮数据库:虚拟线程数量:保留下游并发许可。

05

最后我会主动说明这个方案不适合什么场景。方案:更适合的场景:主要收益:代价与边界。 平台线程池:CPU 密集或并发规模受控:工具成熟、资源上限显式:阻塞并发规模受线程成本限制。 虚拟线程:大量独立阻塞 I/O:同步代码风格、并发成本低:下游限流和 pinning 仍需治理。 响应式模型:已有非阻塞生态和流式背压:少量线程承载大量连接:编排、调试与上下文传播复杂。 选型至少带上 并发线程数、临界区长度、阻塞比例和任务到达速率,并用上面的量化基线验证;