支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

这篇具有很好参考价值的文章主要介绍了支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎访问我的GitHub

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

本篇概览

  • 本篇是《支持JDK19虚拟线程的web框架》系列的第四篇,主要内容是阅读quarkus源码,开阔眼界,了解框架级别的软件是如何使用虚拟线程的,另外再感受一下整体架构设计的重要性,只有良好的设计才能保证新增能力对现有框架不会造成太大影响
  • 另外请放心,虽然quarkus源码复杂,但本文会做到十分克制,不会在虚拟线程之外的地方展开阅读和分析,以保证整篇文章都在聚焦虚拟线程,
  • 本文主要由下图的内容构成,红色区域表示本篇核心:一个特别的Excutor对象,咱们只要搞清楚这个对象是如何创建的,以及如何使用,就弄明白了quarkus框架是如何支持虚拟线程的,另外之前咱们用过的@RunOnVirtualThread注解,在解释Executor对象是从哪来的这个问题时也是决定性的,需要追踪它的具体作用:
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 根据上面的规划,本篇将分为以下三部分展开叙述:
  1. 首先是最具体形象的:前面的代码中,如果要开启虚拟线程就用@RunOnVirtualThread注解去修饰方法,那么咱们首先就要弄明白这个@RunOnVirtualThread注解在代码运行的时候,起到了什么作用?
  2. 其次是本篇的核心:一个Executor对象的前世今生,今天的文章都会围绕它展开,它是虚拟线程的灵魂,所以本文的第二部分就先弄明白这个重要的Executor是怎么诞生的
  3. 最后,也就是最重要的:Executor对象是怎么工作的
  • 接下来直奔主题吧,一头扎入quarkus源码的汪洋,畅游其中

关于quarkus源码

  • 本文中阅读的quarkus源码版本是2.13.3.Final,下载地址:https://codeload.github.com/quarkusio/quarkus/zip/refs/tags/2.13.3.Final

参数isDefaultBlocking,后面多处用到

  • 看源码的第一步,咱们先弄明白一个重要参数:isDefaultBlocking,因为后面的源码阅读有好几处都会用到

  • 关于isDefaultBlocking,其来源是接口RequestContextFactory,如下图,接口的isDefaultBlocking方法,默认返回是false

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 实际运行中,该接口的实现类是ResteasyReactiveRecorder#createDeployment中创建的匿名类,其代码如下,未实现isDefaultBlocking方法,因此依旧是接口定义中的默认方法生效,返回值就是false
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 记住isDefaultBlocking等于false,接下来回到正题:咱们给web服务类添加的@RunOnVirtualThread注解,到底去了哪里?

@RunOnVirtualThread注解去哪了?

  • quarkus应用启动的时候,方法ResteasyReactiveProcessor#setupEndpoints会执行,主要是执行每个endpoint(web服务的可访问地址)的初始化操作,里面会调用EndpointIndexer#createEndpoints方法

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • EndpointIndexer#createEndpoints方法中,会为每个web接口方法创建ResourceMethod对象,里面是此web接口方法的配置信息,注意下面箭头所指位置,ResourceMethod对象的成员变量runOnVirtualThread的取值,来自同名的临时变量

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 从下图可见,那个临时变量runOnVirtualThread其实来自方法isRunOnVirtualThread
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 打开EndpointIndexer#isRunOnVirtualThread方法,如下图,如果某个类的某个方法被添加了@RunOnVirtualThread注解,那么下面的getInheritableAnnotation方法返回的就是从此方法中取得的注解对象

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 至于上图中的getInheritableAnnotation方法,我觉得很有必要看一眼,就一眼...,如下图,可见,@RunOnVirtualThread注解不论是写在方法上还是类上都有效

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 至此,可以小结了:咱们开发web服务的过程中,为web服务类添加的@RunOnVirtualThread,都存入了ResourceMethod对象中
  • 上面这个结论很重要,后面会用到
  • 现在已经顺利弄明白了第一个问题:@RunOnVirtualThread注解去哪了?继续下一个:那个特别的Executor对象是怎么诞生的?

关于Executor

  • 本篇最重要的内容就是一个特别的Executor对象,现在就来聚焦它,先看它的创建过程
  • quarkus应用启动的时候,方法ResteasyReactiveProcessor#setupDeployment会执行,主要是完成应用启动是的一些初始化操作,里面代码很多,下图箭头所指是本篇最关心的,里面会提取bean的注解做对应的处理
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 现在,重点来了!!!
  • 上图红色箭头的代码在ResteasyReactiveRecorder.java中,来看这个createDeployment方法,如下图,第一个箭头处,出现了一个静态变量,名为VIRTUAL_EXECUTOR_SUPPLIER,它先被传给了RuntimeDeploymentManager对象,然后在箭头2位置,RuntimeDeploymentManager对象的deploy中,就会用到这个VIRTUAL_EXECUTOR_SUPPLIER

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 接下来兵分两路,先看上图箭头1中的VIRTUAL_EXECUTOR_SUPPLIER是什么,再看箭头2的deploy中如何使用VIRTUAL_EXECUTOR_SUPPLIER

首先,VIRTUAL_EXECUTOR_SUPPLIER是什么

  • 在看之前,先回顾一下JDK官方指导是如何使用虚拟线程的,如下图,一共两步:先调用Executors.newVirtualThreadPerTaskExecutor()创建一个Executor实例(没错,就是咱们平时写多线程代码时的那个Executor),再执行executor.submit方法,这样就创建了虚拟线程,并在虚拟线程中执行业务逻辑:
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 现在去看创建VIRTUAL_EXECUTOR_SUPPLIER的代码就会特别清晰了,如下图,前面在JDK官方指导看到的Executors.newVirtualThreadPerTaskExecutor(),在quarkus这里被改为用反射实现,这样可以避免JDK19以下的环境中出现编译问题,箭头3位置的代码也很重要,如果当前环境不支持虚拟线程,就会返回一个可用的executor,确保业务能执行下去

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 对于上图箭头3位置的做法,个人并不认同:我使用虚拟线程,就是想一口气创建成千上万线程,再肆无忌惮的使用,遇到不支持虚拟线程的场景,直接抛异常让我知道这条路走不通,逼我再去想办法解决,这样不好么?而箭头3位置显然返回的是传统线程,这么一来,岂不是成了创建成千上万的传统线程了?这谁扛得住?关键是,在开发阶段,因为条件所限,可能只构造了少量线程来验证基本功能,如果就这样发布到生产环境,就有可能创建大量传统线程,导致CPU的内核态使用率上涨,影响系统整体性能
  • 至此,咱们算是搞清楚这个executor是啥了:用Executors.newVirtualThreadPerTaskExecutor()创建的Executor实例,虽然是用反射,但本质上得到的结果和JDK方法的推荐做法一致

其次,RuntimeDeploymentManager#deploy方法里是什么?

  • 刚才说好的兵分两路,先看VIRTUAL_EXECUTOR_SUPPLIER是什么,再看RuntimeDeploymentManager#deploy()方法

  • 该方法内容很多,咱们还是只看虚拟线程有关的,如下图,VIRTUAL_EXECUTOR_SUPPLIER成了runtimeResourceDeployment的成员变量,然后针对每个bean的每个方法,都要执行一次箭头4指向的buildResourceMethod方法,此方法是关键,接下来重点看

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 展开上图箭头4的方法,原来如此,注意箭头指向的method.isRunOnVirtualThread(),这个在前面已经分析过了,咱们用@isRunOnVirtualThread修饰过的web接口,在这里返回的值就是true,就会执行箭头2所指的代码,为此web接口添加一个handler,从名字上看,这个blockingHandlerVirtualThread和之前咱们一直关注的VIRTUAL_EXECUTOR_SUPPLIER应该有不小的关系
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 看RuntimeResourceDeployment的构造方法,果然VIRTUAL_EXECUTOR_SUPPLIER是blockingHandlerVirtualThread构造方法的入参

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 至此就要先打住了,不要急着看BlockingHandler的代码,那里面的东西是在处理web请求时才会执行,到目前为止咱们的重点还只是分析Executors.newVirtualThreadPerTaskExecutor()方法创建的executor去了哪里,现在就小结一下吧

  • 一图胜千言,本篇最核心的Executor对象的诞生过程,由一个主线逻辑和两个支线逻辑组成,如下图,红色代表主线任务,它负责遍历所有web接口对应的方法,发现该方法需要用虚拟线程执行时,就为此方法绑定一个BlockingHandler对象,这个handler的成员变量中,就有直线逻辑用JDK19特定的方法创建出来的虚拟线程特有的executor对象,至于这个handler对象怎么用?就是本篇的另一半重要内容了:执行虚拟线程

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 至此,本篇的第二个重要问题:这个特别的Executor对象是哪来的,这个问题已经弄明白了(好像一句话就能说清楚:放入了和web接口方法关联的handler中),接下来是最后一个问题:这个特别的Executor对象应该怎么用?

这个特别的Executor对象应该怎么用?

  • 由于虚拟线程是在处理web响应的时候被用到的,所以分析这个特别的Executor对象时,不可避免的进入了quarkus处理web响应的复杂逻辑中,之所以说复杂,因为这里面最底层涉及到netty,再往上又涉及到vertx库,如果咱们从头去看会严重偏离主题,所以接下来分析web响应的代码时,我这边就尽量简化了
  • 代码分析中RestInitialHandler#beginProcessing方法开始吧,对于反应式web服务,每次请求都会执行此方法,如下图,红色箭头指向的ResteasyReactiveRequestContext对象需要重点关注,这里面放置了本次web请求的相关信息,接下来就会执行此对象的run方法

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 打开run方法,豁然开朗,前面咱们看到为web接口方法绑定handler,这里会取出handler依次执行
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 上图的方法是在中实现的,打开代码后吓了我一跳,估计quarkus的人也怕被喷,在注释中看到了他们满满的求生欲:代码写成这样是为了性能考虑,这样写就是单态调用,取代了简化写法中的多态调用,会有更好的性能表现(不敢说学到了新技术,只能说开阔了眼界)

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 上面的代码其实就是调用hanler的handle方法,所以,是时候去看那个BlockingHandler的handler方法了

  • 刚打开代码就大呼一声痛快!如下图,handler将虚拟线程的executor和web请求的上下文对象requestContext串起来了,接下来该去箭头2所指的resume中一探究竟,我这里大胆的猜一下,resume方法中要做的事情应该和Runnable有关,理由很简单:Runnable和Executor不就是配合着用的嘛

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 上图箭头2的代码在AbstractResteasyReactiveContext.java中,先看这个AbstractResteasyReactiveContext类,果然实现了Runnable

支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程

  • 接下来该看AbstractResteasyReactiveContext#resume方法了,看之前我猜应该是executor.execute(this),因为我只会这么写...,打开代码一看就乐了,原来我只会这么写就够了,因为他们也是这么写的,注意箭头2,本文的核心也就是这段代码了
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 写到这里,关于executor的使用也全部分析完了,用一个简化图小结吧
支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
  • 至此,quarkus支持虚拟线程的相关代码已经阅读完毕,这里再做个小结:
  1. 咱们在web接口类上添加的@RunOnVirtualThread注解,会存入每个web接口方法对应的ResourceMethod对象中
  2. 应用在初始化的时候,检查web接口方法对应的ResourceMethod对象,如果需要在虚拟线程中响应,就给这个web接口绑定一个BlockingHandler对象,此对象有个成员变量,是个executor,是通过Executors.newVirtualThreadPerTaskExecutor()方法创建的
  3. web请求到达时,web接口方法的handler对象会被拿来执行其handler方法,BlockingHandler也是其中之一
  4. BlockingHandler的handler方法中,会使用executor.execute方法来执行web响应逻辑,此方法会创建创建虚拟线程,在虚拟线程中完成web响应
  • 相比前面三篇的动手实战,本篇主要在阅读quarkus源码,略显枯燥,尽管已尽量用图来辅助理解,但是读源码就是这样,不但捷径很少,岔路还特别多,好在咱们一路咬牙坚持下来了,收获也不会少

后面更精彩

  • 下一篇文章就是整个系列的终篇了,相比本文,终篇会简单很多,大家一起在轻松的氛围中畅谈线程技术的一个重要成员:ThreadLocal,看它在虚拟线程时代如何兴风作浪

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

学习路上,你不孤单,欣宸原创一路相伴...文章来源地址https://www.toymoban.com/news/detail-712239.html

到了这里,关于支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JDK21最终版协程实现之虚拟线程

    JDK9 后的版本你觉得没必要折腾,我也认可,但是JDK21有必要关注。因为 JDK21 引入全新的并发编程模式。 一直沽名钓誉的GoLang吹得最厉害的就是协程了。JDK21 中就在这方面做了很大的改进,让Java并发编程变得更简单一点,更丝滑一点。 之前写过JDK21 Feature。 Virtual Threads 、

    2024年02月08日
    浏览(58)
  • JDK21中虚拟线程到底是什么?看完便知

    本文涉及到的技术:虚拟线程、结构化并发、线程池、TheadLocal,对原理感兴趣的可以直接跳到原理部分。 虚拟线程是JDK19中引入的,JDK21正式发布,我们先来看看虚拟线程的几种用法,然后再来分析底层实现原理。 先定义一个Runnable: 通过观察输出结果,就能知道当前运行

    2024年02月08日
    浏览(43)
  • 【Java】JDK 21中的虚拟线程以及其他新特性

      目录 一、字符串模板(String Templates) 二、序列化集合(Sequenced Collections) 三、分代ZGC(Generational ZGC) 四、记录模式(Record Patterns) 五、Fibers(纤程) 结论 JDK 21是Java开发工具包的最新版本,它引入了许多令人振奋的新特性,旨在提高开发人员的生产力和代码质量。在本

    2024年02月08日
    浏览(44)
  • 响应式编程又变天了?看JDK21虚拟线程如何颠覆!

    本文解释为啥会有响应式编程,为什么它在开发者中不太受欢迎,以及引入 Java 虚拟线程后它可能最终会消失。 命令式风格编程一直深受开发者喜爱,如 if-then-else、while 循环、函数和代码块等结构使代码易理解、调试,异常易追踪。然而,像所有好的东西一样,通常也有问

    2024年02月05日
    浏览(33)
  • JDK 21预告:虚拟线程正式发布及十多项新特性

    Java 21进入发布候选阶段,其中包括15个最终特性,包括虚拟线程、分代Z垃圾收集器和密钥封装机制API。 JDK21计划于9月19日作为Oracle标准Java实现的下一个LTS版本发布,已进入发布候选(RC)阶段。Java 21将具有15个新特性,之前提议的第16个特性实验性Shenandoah垃圾收集器已在6月被舍

    2024年02月10日
    浏览(42)
  • 再见了Future,图解JDK21虚拟线程的结构化并发

    Java为我们提供了许多启动线程和管理线程的方法。在本文中,我们将介绍一些在Java中进行并发编程的选项。我们将介绍 结构化并发 的概念,然后讨论 Java 21 中一组预览类——它使将任务拆分为子任务、收集结果并对其进行操作变得非常容易,而且不会不小心留下任何挂起的

    2024年02月05日
    浏览(56)
  • 19个Web前端交互式3D JavaScript框架和库

    JavaScript (JS) 是一种轻量级的解释(或即时编译)编程语言,是世界上最流行的编程语言。JavaScript 是一种基于原型的多范式、单线程的动态语言,支持面向对象、命令式和声明式(例如函数式编程)风格。JavaScript 几乎可以做任何事情,更可以在包括物联网在内的多个平台

    2024年02月22日
    浏览(44)
  • 【昕宝爸爸小模块】深入浅出之JDK21 中的虚拟线程到底是怎么回事(一)

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 虚拟线程这个

    2024年01月16日
    浏览(45)
  • 【昕宝爸爸小模块】深入浅出之JDK21 中的虚拟线程到底是怎么回事(二)

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 上一篇博文:

    2024年01月16日
    浏览(44)
  • [JDK8环境下的HashMap类应用及源码分析] 看源码了解HashMap的扩容机制

    🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄、CSDN博客专家 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 [Java基础] StringBuffer 和 StringBuilder 类应用及源码分析 [Java基础] 数组应用及源码分析 [Java基础] String,分析

    2024年02月10日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包