首页IT科技jvm 虚拟内存(支持JDK19虚拟线程的web框架,之三:观察运行中的虚拟线程)

jvm 虚拟内存(支持JDK19虚拟线程的web框架,之三:观察运行中的虚拟线程)

时间2025-08-02 02:11:36分类IT科技浏览5422
导读:欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码 :https://github.com/zq2599/blog_demos...

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

《支持JDK19虚拟线程的web框架》系列文章链接

支持JDK19虚拟线程的web框架                ,之一:体验 支持JDK19虚拟线程的web框架                      ,之二:完整开发一个支持虚拟线程的quarkus应用 支持JDK19虚拟线程的web框架       ,之三:观察运行中的虚拟线程 支持JDK19虚拟线程的web框架            ,之四:看源码                       ,了解quarkus如何支持虚拟线程 支持JDK19虚拟线程的web框架          ,之五(终篇):兴风作浪的ThreadLocal

本篇概览

本篇是《支持JDK19虚拟线程的web框架》系列的第三篇        ,在前面两篇咱们一起了解和体验了支持虚拟线程的web服务                        ,功能性能都试过              ,整个开发过程也完整执行    ,算是对quarkus和虚拟线程有了初步的了解                        ,但也留下两个问题 虚拟线程和常规子线程的区别                  ,究竟能不能看出来?前文已经验证了性能上区别不大,那还有别的方式来观察和区分吗? 能不能稍微深入一点                    ,仅凭一个@RunOnVirtualThread注解就强行写两篇博客                      ,实在是太忽悠人了 本文聚焦第一个问题    ,与大家一起深入了解虚拟线程                ,重点在理论结合实际                      ,将官方资料在实战中得到印证 至于第二个问题       ,留待下一篇...

设置

开始深入学习前有个设置需要确认            ,否则会导致访问服务失败                       ,请打开前文开发的quarkus应用          ,下图红色箭头指向的配置必须存在        ,且值必须是0.0.0.0 如果没有上述配置                        ,IDEA启动的应用就只会监听127.0.0.1这块网卡              ,如此依赖外部测试工具访问此应用的服务就无法成功 那么就开始吧:如何直观地              、清楚地看出虚拟线程和常规子线程的区别?

准备工作

工欲善其事.....咱们先把必要的工具装上:IDEA的JProfiler插件    ,安装步骤如下图 接下来请在自己电脑上安装JProfiler                        ,注意                  ,这一步必须要做,详细的安装和注(po)册(jie)过程就不写在本文中了                    ,请自行搜索相关资料 完成上述准备后                      ,点击下图箭头所指按钮    ,这样就指定了JProfiler去监控分析启动后的应用进程 IDEA会拉起JProfiler 出现新的窗口如下图                ,再点击右下角的确定按钮 现在JProfiler已经在监控quarkus应用的进程了                      ,界面如下 如下图       ,点击线程历史菜单            ,就能看到当前应用进程内的所有线程                       ,注意按照步骤2过滤一下          ,只看存活的线程 接下来        ,咱们就要用JProfiler来观察常规线程和虚拟线程的区别了 先回忆一下                        ,前文中              ,咱们开发的quarkus应用有两个web服务类    ,分别是:

VTPersonResource.java                        ,该服务类使用了虚拟线程来执行web响应                  ,对应web路径:/vt/persons

PoolPersonResource.java,该服务类未使用虚拟线程                    ,所以执行web响应的是传统线程池中的子线程                      ,对应web路径:/pool/persons

接下来    ,压测工具k6先后压测上述两个接口                ,用JProfiler观察进程中线程的变化情况

不使用虚拟线程时的线程状况

咱们先发请求到/pool/persons                      ,也就是先不用虚拟线程       ,看看传统线程池响应web服务的时候            ,在JProfiler中是啥样的 像《上篇》那样                       ,用K6压测接口/pool/persons          ,脚本如下        ,注意IP地址不能用localhost                        ,因为这是在docker容器内运行的              ,localhost代表容器的回环网卡    ,而并非宿主机的: import http from k6/http; import { sleep, check } from k6; export let options = { vus: 10, duration: 60s, }; export default function () { let r = Math.floor(Math.random() * 6) + 1; const res = http.get(`http://192.168.3.187:8080/pool/persons/${r}`); check(res, { is status 200: (res) => res.status === 200, body size is > 0: (r) => r.body.length > 0, }); sleep(1); } 在压测期间去看JProfiler                        ,如下图红框                  ,新增了10个线程,它们就是负责处理web响应的线程(前文的实战中                    ,我们已见过web响应的内容                      ,里面就有线程名称    ,红框中的和它们一致) 下图是K6的测试报告                ,可见一共发起了570次请求                      ,然而压测期间JProfiler上新增的线程只有上图中的十个       ,这也印证了线程池的逻辑:每个线程执行完业务逻辑后            ,回到线程池                       ,下一次请求到来时          ,该线程继续执行业务逻辑 k6压测结束后        ,等上三十秒再去看JProfiler                        ,如下图              ,那些处理web响应的子线程已经不见了(或者说不是存活状态了) 如果您熟悉Java的线程池原理    ,对以上情况就一目了然:线程池空闲时                        ,保留线程数不超过corePoolSize 既然看过了传统线程池的服务情况                  ,接着改看虚拟线程的情况了,两边对比着看收获一定不小

思考:用JProfiler观察虚拟线程                    ,你到底想收获什么?(本篇精华段落)

大家好                      ,接下来这一段话    ,个人觉得是本篇的精华                ,因为这是欣宸自己在迷茫中找到方向的一种方法(或者套路)                      ,希望能给您带来参考

在用JProfiler观察虚拟线程之前       ,咱们先来捋捋:接下来咱们究竟想看到什么            ,能用文字说清楚吗?这个问题很重要!

仅仅是想看一眼虚拟线程吗?那无非就是看到几个新增的线程                       ,名字有些特殊          ,仅此而已        ,这能有啥收获?

不要急于动手                        ,咱们都应该冷静下来              ,认真思考    ,让这个问题能用文字表达出来                        ,而不是仅仅在心中有个运行JProfiler的冲动:借助JProfiler                  ,咱们真正想要的是证虚拟线程的来龙去脉,也就是把官方文档中的理论                    ,在JProfiler中找到实现!

所以                      ,先阅读虚拟线程的官方文档吧    ,放心                ,咱们只看最关键的部分即可                      ,不会涉及长篇大论

打开java官方文档       ,找到虚拟线程定义的那段            ,如下图                       ,注意红框中的内容以及我的中文注解(我将下面这幅图称为本篇最有价值的地方)

没错          ,官方文档虽多        ,但咱们没必要全看                        ,上面这段才是关键              ,看完后捋捋流程图如下 看到上图    ,您应该会有以下三个疑惑: ForkJoin线程池啥时候创建的?会不会销毁? 调度器(scheduler)啥时候创建的?会不会销毁? carrier啥时候创建的?会不会销毁? 如果这些关键问题没说清楚                        ,上面的流程图算不算是捋了个寂寞... 要想搞清楚为什么没有回答上面三个问题                  ,咱们把官方文档滚动到最顶部,如下图 上图红框表明                    ,这是一篇JEP文档                      ,即: JDK Enhancement Proposal     ,这类文档只提出标准                ,而非实现                      ,真正实现的这个标准的       ,是各个JVM虚拟机厂家(例如Oracle)            ,所以                       ,要想回答上面三个问题          ,只能去查找具体JDK软件的实现 简单的说:别纠结那三个问题        ,我答不上来... 咱们继续                        ,接下来更精彩 看过官方资料后              ,再回到最初的问题    ,咱们想通过JProfiler得到什么?相信您已经很清楚了吧                        ,我觉得是这三样: 调度器                  ,scheduler(ForkJoin线程池中的线程) 执行虚拟线程任务的真实线程,carrier 虚拟线程 现在开始压测吧                    ,继续用k6                      ,如下图    ,脚本中的地址要改成使用虚拟线程的web服务 压测期间去观察JProfiler                ,如下图                      ,完全符合预期       ,说实话            ,第一次看到这些内容时                       ,自己的内心是很激动的          ,这种知识点得到印证的感觉真是太好了 再看看那些不再存活的线程        ,如下图                        ,大量VirtualThreads存在              ,这也符合虚拟线程的特性:不复用    ,执行完毕就结束 等到压测结束后                        ,scheduler                       、carrier        、虚拟线程                  ,它们都不再存活,如下图 如此看来                    ,在执行任务的时候                      ,会出现sheduler和carrier来完成虚拟线程中的任务    ,等到这些任务执行完毕                ,所有真实线程           、虚拟线程都被结束                      ,不再存活 至此       ,借助JProfiler观察常规线程和虚拟线程的实战就完成了            ,经过了这些理论结合实际的操作和分析                       ,相信您对虚拟线程的认知已经更具体和全面          ,如今它不再神秘或者高深莫测        ,咱们也更有信心学好它用好它

我有个想法

码字码到这里                        ,我想抛出一个大胆的想法和大家一起讨论:今天咱们借助JProfiler观察到了scheduler                      、carrier            、虚拟线程等的创建        、运行                      、结束等过程              ,我这里用的虚拟机是azul JDK    ,所以JProfiler中看到的也只是azul JDK对虚拟线程规范的实现情况                        ,如果换成其他JDK                  ,例如Oracle JDK,那么在JProfiler中看到的scheduler                、carrier    、虚拟线程它们会不会有所不同呢?(例如scheduler可能会存活得久一些)毕竟JEP 425只是个标准                    ,没有明确规定实现                      ,而azul JDK和Oracle JDK属于不同厂商的实现 当然了这只是个猜测    ,篇(lan)幅(de)所(dong)限(shou)就不在本篇做这些事情了                ,当我相信会有爱动手的读者去实战操作的                      ,麻烦您告诉欣宸一下您的验证结果       ,谢谢啦! 写到这里            ,虚拟线程的文章可以完结了吗?不会                       ,接下来咱们还要畅游quarkus          ,揭秘@RunOnVirtualThread注解背后的故事        ,看看优秀的框架是如何玩转虚拟线程的                        ,上广告词:欣宸原创              ,不辜负您的期待!

欢迎关注博客园:程序员欣宸

学习路上    ,你不孤单                        ,欣宸原创一路相伴...

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
国外主机品牌(IXWebHosting美国主机商品牌全线关闭) arm交叉编译器安装(RK3588移植-opencv交叉编译aarch64)