0

0

如何利用Java 21虚拟线程优化I/O密集型任务_QPS提升方案实战

P粉602998670

P粉602998670

发布时间:2026-02-27 13:52:04

|

135人浏览过

|

来源于php中文网

原创

能,但仅当大量阻塞在传统i/o(如read、accept、jdbc)且下游资源(连接池等)已扩容时成立;对非阻塞api无效,cpu密集型任务需隔离,迁移需分层控制并修复类加载器、监控等兼容性问题。

如何利用java 21虚拟线程优化i/o密集型任务_qps提升方案实战

虚拟线程在 I/O 密集型任务中真能提升 QPS?

能,但只在特定条件下成立:当任务大量阻塞在 InputStream.read()Socket.accept()、数据库连接等待、HTTP 客户端同步调用等传统阻塞 I/O 上时,虚拟线程才显著降低线程调度开销。它不加速单次 I/O,而是让成千上万个并发请求不再被平台线程数量卡死。

常见错误现象是:升级 Java 21 后直接把 new Thread() 换成 Thread.ofVirtual().start(),结果 QPS 没涨反降——因为没关掉旧的线程池或没适配阻塞调用链。

  • 必须确保底层 I/O 操作本身仍是阻塞式(如 JDK 自带 HttpURLConnection、JDBC 驱动默认模式),虚拟线程对非阻塞 API(如 Netty、WebFlux)无增益,甚至因额外调度开销略降性能
  • 不要在虚拟线程里执行长时间 CPU 计算(> 10ms),否则会抢占调度器,拖慢其他虚拟线程;这类逻辑需显式提交到 ForkJoinPool.commonPool() 或专用线程池
  • Spring Boot 3.2+ 默认启用虚拟线程支持,但 Spring MVC 的 @RestController 方法只有在未配置自定义 TaskExecutor 时才会自动运行在虚拟线程上

怎么安全地把现有 Tomcat 应用迁入虚拟线程?

不能全局替换线程模型,要分层控制:让 Web 层接收请求的线程变成虚拟线程,但数据库/缓存等客户端仍走固定大小的平台线程池,避免压垮下游。

Tomcat 10.1.12+ 支持 virtual-thread-enabled="true",但仅限于 connector 层;业务逻辑是否跑在虚拟线程上,取决于你是否用了 Executors.newVirtualThreadPerTaskExecutor() 或 Spring 的 @Async 配置。

立即学习Java免费学习笔记(深入)”;

Mojo
Mojo

Mojo: 创作动人的视频故事

下载
  • Tomcat 配置示例:
    <Connector port="8080" protocol="HTTP/1.1" virtual-thread-enabled="true" />
  • Spring Boot 中禁用默认线程池:设置 spring.task.execution.pool.max-size=1 并启用虚拟线程调度器(spring.threads.virtual.enabled=true
  • 已有 CompletableFuture.supplyAsync() 调用需显式传入虚拟线程执行器:supplyAsync(() -> ..., Executors.newVirtualThreadPerTaskExecutor()),否则仍在 ForkJoinPool 中运行

Thread.start()Thread.ofVirtual().start() 行为差异在哪?

最关键是调度粒度和生命周期管理:平台线程绑定 OS 线程,启动慢、数量受限;虚拟线程由 JVM 调度,在阻塞点自动挂起/恢复,几乎无创建成本。

但这也带来一个隐蔽坑:虚拟线程默认不继承上下文类加载器(contextClassLoader),很多老框架(如早期 Druid、Logback)依赖它加载资源,会导致 ClassNotFoundException 或日志不输出。

  • 修复方式:手动设置,例如
    Thread.ofVirtual().unstarted(() -> {<br>  Thread.currentThread().setContextClassLoader(MyApp.class.getClassLoader());<br>  doWork();<br>});
  • 虚拟线程无法被 ThreadMXBean 直接监控,jstack 也不显示完整堆栈;排查问题得靠 jcmd <pid> VM.native_memory summary</pid> 或 JFR 事件 jdk.VirtualThreadSubmitFailed
  • 调试时别用 Thread.sleep(1000) 模拟延迟——它会让虚拟线程主动让出调度权,行为不像平台线程,可能掩盖竞态问题

为什么数据库连接池成了虚拟线程 QPS 提升的最大瓶颈?

因为虚拟线程再轻量,也得等连接池分配连接;而 HikariCP、Druid 默认最大连接数通常设为 20~50,远低于你能轻松启动的数万虚拟线程,结果大量线程在 HikariPool.getConnection() 处排队阻塞,QPS 卡死。

这不是虚拟线程的问题,是资源错配:你放大了“请求并发能力”,却没放开“下游连接供给”。真实压测中,90% 的 QPS 上不去案例都卡在这里。

  • 必须调高连接池 maximumPoolSize,建议按预期峰值 QPS × 平均 SQL 响应时间(秒)估算,例如 QPS=2000、平均耗时 50ms → 至少需要 100 连接
  • 避免使用 Connection.close() 后立即释放连接回池——某些驱动(如 PostgreSQL 的 pgjdbc)在虚拟线程下 close 调用可能触发同步清理,改用 try-with-resources 保证及时归还
  • 如果数据库本身扛不住高并发连接(如 MySQL 默认 max_connections=151),那就得加读写分离、分库分表,或者切到异步驱动(如 R2DBC),否则虚拟线程只是把压力从前端转移到数据库连接队列

真正难的不是开虚拟线程,是识别哪些环节还在用平台线程思维做资源规划——连接池大小、HTTP 客户端超时设置、日志异步刷盘线程数,这些地方不动,光换线程模型只是把瓶颈从 A 点移到 B 点。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

1047

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

339

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

379

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1884

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

378

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

1437

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

585

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

437

2024.04.29

Golang 高级特性与最佳实践:提升代码艺术
Golang 高级特性与最佳实践:提升代码艺术

本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。

0

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.9万人学习

C# 教程
C# 教程

共94课时 | 10.2万人学习

Java 教程
Java 教程

共578课时 | 72.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号