Tomcat 配合虚拟线程,一种新的编程体验
Java 21 在今年早些时候的 9 月 19 日就正式发布,并开始正式引入虚拟线程,但是作为 Java 开发生态中老大哥 Spring 并没有立即跟进,而是在等待了两个月后的 11 月 29 日,伴随着 Spring Boot 3.2 版本的发布,在这个版本中也终于是引入了对虚拟线程的支持。
虚拟线程的引入标志着 Java 在现代编程世界中对编写高吞吐量、高并发应用程序提供了更加完美的支持。
本文我就带着大家一起深入了解一波 Tomcat 配合虚拟线程会带来怎样的效果以及虚拟线程对以后使用 Java 开发高吞吐量、高并发应用程序时所带来的改变。
本文大纲如下,

Tomcat 使用虚拟线程
启用虚拟线程
在 Spring Boot 3.2 中,使用 Tomcat 作为 web 容器时,启用虚拟线程只需要将 spring.threads.virtual.enabled 属性设置为 true。
这样 Spinrg Boot 在启动 Tomcat 容器时会使用一个虚拟线程执行器来代表原有的平台线程池。
注意这里是虚拟线程执行器,不是虚拟线程池哦。
源码解析
在 Spring Boot 3.2 版本以前,Tomcat 默认的线程池使用的就是 Java 提供的 ThreadPoolExecutor 线程池,在 3.2 版本以后,Spring Boot 修改了创建线程池的方法如下所以,


可以看到 Tomcat 会先判断是否启用了虚拟线程,启用了的话就直接创建一个虚拟线程执行器 VirtualThreadExecutor。
VirtualThreadExecutor 类是 Tomcat 为了使用虚拟线程作为执行器而新增的。他的内部代码中针对每个请求任务都是依赖 Jre21Compat 类处理的。
Jre21Compat 类则是 Tomcat 为了兼容 Java21 版本虚拟线程新增的一个兼容类。这个类利用反射方法来调用 Thread.ofVirtual().start(() -> {}) 方法,以便进行任务处理,代码截图如下,


虽然以上代码可以启用 Tomcat 的虚拟线程支持。但是在 Spring Boot 中其实不是这样设置的。还记得上文提到的在 Spring Boot 3.2 中,使用 Tomcat 作为 web 容器时,启用虚拟线程只需要将 spring.threads.virtual.enabled 属性设置为 true 吗?
Spring Boot 3.2 中是通过 tomcatVirtualThreadsProtocolHandlerCustomizer 方法来兼容虚拟线程启用逻辑的,@ConditionalOnThreading(Threading.VIRTUAL) 条件用判断 spring.threads.virtual.enabled 属性是否启用。代码如下,


到这里其实本文所需要讲的涉及源码的部分就全部讲完了。可以看到 Tomcat 引入虚拟线程并不复杂,引入后不在需要维护线程池,减轻了执行器的复杂度。
虚拟线程带来的改变
不知道大家注意到源码中一个改变没有,就是在 Spring Boot 3.2 中,启用了虚拟线程后,Tomcat 默认使用的虚拟线程执行器不在需要池化。
也就是说,在 Spring Boot 3.2 以后的版本里,我们不在需要设置 server.tomcat.threads.max 以及 server.tomcat.threads.min-spare 两个属性以控制 Tomcat 线程池的大小了,因为它压根没有使用平台线程池。
对于 Tomcat 来说,引入虚拟线程,不必在为线程池的维护而费心,还能减轻编程的复杂度。
虚拟线程由 JVM 平台负责进行调度,它是廉价且轻量级的,Tomcat 可以使用 “每个请求一个线程” 模型,而不必担心实际需要多少个线程。
就算请求任务在虚拟线程中调用阻塞 I/O 操作,导致运行时虚拟线程被挂起阻塞,但是只要挂起结束后该虚拟线程就可以恢复。
使用了虚拟线程后,程序员使用普通的阻塞 API,也可以让程序对硬件的利用达到近乎完美水平,以此提供高水平的并发性,从而实现高吞吐量。
可以说,虚拟线程的引入,以后程序员就算是使用 Java 中阻塞 API 也可以开发出高性能、高吞吐量的应用程序。
jmter 实测
在本文中,我还将给各位展示一波 newbeepro 项目升级到 Spring Boot 3.2 后启用虚拟线程所带来的性能提升。
测试服务器
- 主机名称 VM-16-5-centos
- 发行版本 centos-7.9.2009
- 内核版本 3.10.0-1160.88.1.el7.x86_64
- 系统类型 x86_64
- 系统配置:2 核 4 G 5M 带宽

测试项目
newbee-mall-pro 是 newbee-mall 商城的 pro 版本实现了推荐算法、商品秒杀、优惠卷使用,滑块验证码,支付宝支付,中文分词检索等高级功能。
测试方法
使用 newbee-mall-pro 作为测试项目将启用虚拟线程以及未启用虚拟线程的两次设置部署到测试服务器上。
启动容器:amazoncorretto:21.0.1
启动参数:java -jar -Xms1024m -Xmx1024m /opt/newbeemall/newbee-mall.jar
部署后测试地址:http://62.234.206.94/newbeemall/index
测试接口为秒杀接口:/newbeemall/seckill/2/c81e728d9d4c2f636f067f89cc14862c/executionFour
压测设置:启用 2000 个线程,每个线程循环执行 30 秒左右。一共测试五轮,先预热 JVM 后,取吞吐量最大值。
测试数据
启用虚拟线程
压测结果如下,


可以看到 CPU 占用达到百分之 142,内存占用达到百分之 35 的情况下,压测吞吐量最大可以达到 1731。
不启用虚拟线程
考虑到有 2000 个线程进行压测,所以将 Tomcat 线程池的最大线程数也设置到 2000,如下图,

压测结果如下,


可以看到 CPU 占用达到百分之 170,内存占用达到百分之 35 的情况下,压测吞吐量可以达到 1492。
OK,到这里我们可以看到在 Spring Boot 3.2 版本中,使用了虚拟线程的 Tomcat 对比不用虚拟线程时,吞吐量提升差不多有 20%。
在更高并发的测试中,这个差距会越来越明显。因为 Tomcat 使用的平台线程过多时,上下文切换开销会越来越大,而且虚拟线程比平台线程占用更少的内存,一个虚拟线程只占用几 kb 到几十 kb 内存。可以轻松创建上万虚拟线程,降低资源占用同时提高并发。
最后聊两句
虚拟线程带给了现代程序员新的编程体验,使用阻塞编程也能开发出高性能应用程序,而避免了异步模型的编程复杂度,随着更多的框架接入虚拟线程,相信虚拟线程会在未来大放异彩。
关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、国外优质文章翻译等,您的关注将是我的更新动力!
Tomcat 配合虚拟线程,一种新的编程体验的更多相关文章
- 在Tomcat中启用虚拟线程特性
前提 趁着国庆前后阅读了虚拟线程相关的源码,写了一篇<虚拟线程 - VirtualThread源码透视>,里面介绍了虚拟线程的实现原理和使用示例.需要准备做一下前期准备: 安装OpenJD ...
- Tomcat之虚拟主机配置以及web应用配置
Tomcat之虚拟主机配置以及web应用配置 Tomcat文件夹结构例如以下: bin ---- 启动和关闭须要的bat文件所在的文件夹 conf --- 配置文件夹 lib --- tomcat执 ...
- 虚拟线程 - VirtualThread源码透视
前提 JDK19于2022-09-20发布GA版本,该版本提供了虚拟线程的预览功能.下载JDK19之后翻看了一下有关虚拟线程的一些源码,跟早些时候的Loom项目构建版本基本并没有很大出入,也跟第三方J ...
- JSP之WEB服务器:Apache与Tomcat的区别 ,几种常见的web/应用服务器
注意:此为2009年的blog,注意时效性(针对常见服务器) APACHE是一个web服务器环境程序 启用他可以作为web服务器使用 不过只支持静态网页 如(asp,php,cgi,jsp)等 ...
- 1.tomcat部署项目的几种方式和weblogic部署方式及一点通讯
第一种部署方式: 直接使用myeclipse 找到server服务 添加要部署的项目Add Deployment ,然后选中某个项目,首选Exploded Archive(development ...
- tomcat建立虚拟主机
WEB浏览器与WEBserver建立连接后,除了将请求URL中的资源路径发送给WEBserver外,还会将URL中的主机名部分作为HTTP请求消息的Host头发送给WEBserver.比如,在浏览器地 ...
- tomcat关闭后线程依然运行解决办法
tomcat关闭后线程依然运行解决办法,设置线程为守护线程 守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户 ...
- 详解tomcat连接数和线程数
前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...
- Tomcat 连接数与线程池详解
前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...
- Java将增加虚拟线程,挑战Go协程
我们知道 Go 语言最大亮点之一就是原生支持并发,这得益于 Go 语言的协程机制.一个 go 语句就可以发起一个协程 (goroutin).协程本质上是一种用户态线程,它不需要操作系统来进行调度,而是 ...
随机推荐
- AVR汇编(二):AVR架构介绍
AVR汇编(二):AVR架构介绍 ATmega328P介绍 ATmega328P是Atmel公司(现Microchip公司)推出的一个基于AVR架构的高性能低功耗单片机,拥有32KB的Flash.1K ...
- 用 GPT-4 给开源项目 GoPool 重构测试代码 - 每天5分钟玩转 GPT 编程系列(8)
目录 1. 好险,差点被喷 2. 重构测试代码 2.1 引入 Ginkgo 测试框架 2.2 尝试改造旧的测试用例 2.3 重构功能测试代码 3. 总结 1. 好险,差点被喷 早几天发了一篇文章:&l ...
- 《SQL与数据库基础》12. SQL优化
目录 SQL优化 数据插入 insert优化 大批量插入数据 主键优化 order by优化 group by优化 limit优化 count优化 count用法 update优化 本文以 MySQL ...
- 《Hadoop大数据技术开发实战》新书上线
当今互联网已进入大数据时代,大数据技术已广泛应用于金融.医疗.教育.电信.政府等领域.各行各业每天都在产生大量的数据,数据计量单位已从B.KB.MB.GB.TB发展到PB.EB.ZB.YB甚至BB.N ...
- 🖖少年,该升级 Vue3 了!
你好,我是 Kagol. 前言 根据 Vue 官网文档的说明,Vue2 的终止支持时间是 2023 年 12 月 31 日,这意味着从明年开始: Vue2 将不再更新和升级新版本,不再增加新特性,不再 ...
- 【python技巧】文本处理-re库字符匹配
目录 1. 正则表达式 1.1 测试工具 1.2 限定符 1.3 字符集 1.4 运算符 1.5 元字符 1.6 懒惰匹配和贪婪匹配 我们读取文件内容,肯定不是单纯为了输出或者重新写入,对于文本我们一 ...
- Linux系列教程——Linux发展介绍、Linux系统安装、查看Linux内核版本和系统版本、Centos7安装jdk1.8
文章目录 1 Linux发展介绍 零 什么是Linux 一 Linux前身 二 Linux诞生 三 开源文化 四 Linux系统特点 五 Linux分支 2 Linux系统安装 Linux虚拟机安装 ...
- DBA容灾与备份恢复:闪回应用及实践(一)
闪回应用及实践 针对主机故障.网络故障.系统软件故障.存储介质故障.人为操作失误等各类故障,可以通过RAC.RMAN.Data Guard等成熟的解决方案来处理,不过对于人为操作失误防范的首推技术还是 ...
- P6346 [CCO2017] 专业网络 & CF1251E1 Voting(Easy Version)
analysis 这个题目我们可以考虑用贪心来做. 我们不难看出来,这个题目是要让我们推出这么个结论:花小钱,办大人. 整体贪心的思路就出来了,然后就是实现部分. 因为我们认识的人随便是谁都可以.所以 ...
- FFmpeg H.264编码器指南[译]
H264 视频编码器指南 本指引着眼于x264编码器,这里假设你的FFmpeg 编译了--enable-libx264支持.如果你需要编译支持的帮助请看这篇文档:https://trac.ffmpeg ...