iis服务器助手广告广告
返回顶部
首页 > 资讯 > 服务器 >解析在Tomcat中启用虚拟线程特性
  • 212
分享到

解析在Tomcat中启用虚拟线程特性

2024-04-02 19:04:59 212人浏览 泡泡鱼
摘要

目录前提引入依赖编程式初始化Tomcat暂时无法在SpringBoot体系中使用小结前提 趁着国庆前后阅读了虚拟线程相关的源码,写了一篇《虚拟线程 - VirtualThread源码

前提

趁着国庆前后阅读了虚拟线程相关的源码,写了一篇《虚拟线程 - VirtualThread源码透视》,里面介绍了虚拟线程的实现原理和使用示例。需要准备做一下前期准备:

  • 安装Openjdk-19或者oracle JDK-19
  • 准备好嵌入式Tomcat的依赖,需要引入三个依赖包,分别是tomcat-embed-coretomcat-embed-eltomcat-embed-websocket,版本选用10.1.0+

查看Tomcat官方文档的CHANGELOG

支持Loom项目Tomcat最低版本为10.1.0-M16,对应的正式版是10.1.0(当前时间为2022-10-07前后),低于此版本因为大量api还没有适配虚拟线程,主要是没有改造监视器的引用导致虚拟线程pin到载体(平台)线程等问题,因此别无他选。另外,重要的提醒说三次:

  • 本文是实验性质,在未完全证实改造功能可以应用生产环境前需要谨慎评估,或者先别使用于生产环境
  • 本文是实验性质,在未完全证实改造功能可以应用生产环境前需要谨慎评估,或者先别使用于生产环境
  • 本文是实验性质,在未完全证实改造功能可以应用生产环境前需要谨慎评估,或者先别使用于生产环境

引入依赖

引入以下依赖:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>10.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-el</artifactId>
    <version>10.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-WEBSocket</artifactId>
    <version>10.1.0</version>
</dependency>

编程式初始化Tomcat

为了使用反射调用一些java.base模块下没开放的依赖包和跟踪虚拟线程栈,程序运行时候加入下面的VM参数:

--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED -Djdk.tracePinnedThreads=full

idea的运行配置中是这个样子:

接着编写一个httpservlet实现:

public class VirtualThreadHandleServlet extends HttpServlet {

    private static final DateTimeFORMatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Thread thread = Thread.currentThread();
        System.out.printf("service by thread ==> %s, is virtual ==> %s, carrier thread ==> %s\n",
                thread.getName(), thread.isVirtual(), getCurrentCarrierThreadName(thread));
        resp.setStatus(HttpServletResponse.SC_OK);
        resp.setHeader("Content-Type", "application/JSON");
        String content = "{\"time\":" + "\"" + LocalDateTime.now().format(FORMATTER) + "\"}";
        resp.getWriter().write(content);
    }

    private static String getCurrentCarrierThreadName(Thread currentThread) {
        if (currentThread.isVirtual()) {
            try {
                MethodHandle methodHandle = MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup())
                        .findStatic(Thread.class, "currentCarrierThread", MethodType.methodType(Thread.class));
                Thread carrierThread = (Thread) methodHandle.invoke();
                return carrierThread.getName();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        return "UNKNOWN";
    }
}

Servlet实现比较简单,就是在控制台打印一些虚拟线程和载体线程的一些信息,然后返回HTTP状态码为200和一个jsON字符展示当前精确到毫秒的时间。接着编写一个main方法初始化Tomcat

public class EmbedTomcatVirtualThreadDemo {

    private static final String SERVLET_NAME = "VirtualThreadHandleServlet";

    private static final String SERVLET_PATH = "
    public static void main(String[] args) throws Throwable {
        String pinMode = System.getProperty("jdk.tracePinnedThreads");
        System.out.println("pin mode = " + pinMode);
        Tomcat tomcat = new Tomcat();
        Context context = tomcat.addContext("", (new File(".")).getAbsolutePath());
        Tomcat.addServlet(context, SERVLET_NAME, new VirtualThreadHandleServlet());
        context.addServletMappingDecoded(SERVLET_PATH, SERVLET_NAME);
        Connector connector = new Connector();
        ProtocolHandler protocolHandler = connector.getProtocolHandler();
        if (protocolHandler instanceof AbstractProtocol<?> protocol) {
            protocol.setAddress(InetAddress.getByName("127.0.0.1"));
            protocol.setPort(9091);
            ThreadFactory factory = Thread.ofVirtual().name("embed-tomcat-virtualWorker-", 0).factory();
            Class<?> klass = Class.forName("java.util.concurrent.ThreadPerTaskExecutor");
            MethodHandle methodHandle = MethodHandles.privateLookupIn(klass, MethodHandles.lookup())
                    .findStatic(klass, "create", MethodType.methodType(klass, new Class[]{ThreadFactory.class}));
            ExecutorService executor = (ExecutorService) methodHandle.invoke(factory);
            protocol.setExecutor(executor);
        }
        tomcat.getService().addConnector(connector);
        tomcat.start();
    }
}

这里VirtualThreadHandleServlet匹配所有格式的请求路径并且处理所有请求方法类型的请求。默认的虚拟线程调度器没有为虚拟线程设置名称,也就是如果使用Executors.newVirtualThreadPerTaskExecutor()作为Tomcat线程池是最终调用看到的控制台输出的虚拟线程名称是一个空字符串。所以笔者这里用MethodHandle直接实例化了默认修饰符没有开放访问权限的ThreadPerTaskExecutor类,基于一个自定义的ThreadFactory强制构造了一个自定义ThreadPerTaskExecutor实例。调用main方法启动后见控制台输出:

这里确认了Tomcat启动完成侦听127.0.0.1:9091,通过浏览器或者POSTMAN发送任意请求例如http://127.0.0.1:9091/foo就能看到响应结果和控制台输出:

这里的Tomcat线程池甚至可以设计为一个完全自定义的虚拟线程调度器,可以参考前面一篇文章,这里不再赘述。

暂时无法在springBoot体系中使用

由于Servlet规范问题,Tomcat的升级导致一些接口迁移到jakarta.servlet包中,例如jakarta.servlet.Servlet,此时SpringBoot体系即使是最新版本(当前时间为2022-10-07前后,此时最新版本为2.7.4)使用的是还是旧的规范,对应的类是javax.servlet.Servlet,这只是其中一个接口,大部分和HTTP协议或者Servlet规范相关的接口都存在这个包升级不兼容的问题,需要等待SpringBoot升级为embed-tomcat-*-10.1.0+才能适配虚拟线程。

小结

Demo项目仓库:

GitHub:https://github.com/zjcscut/framework-mesh/tree/master/tomcat-virtual-thread

到此这篇关于在Tomcat中启用虚拟线程特性的文章就介绍到这了,更多相关Tomcat启用虚拟线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 解析在Tomcat中启用虚拟线程特性

本文链接: https://www.lsjlt.com/news/168875.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解析在Tomcat中启用虚拟线程特性
    目录前提引入依赖编程式初始化Tomcat暂时无法在SpringBoot体系中使用小结前提 趁着国庆前后阅读了虚拟线程相关的源码,写了一篇《虚拟线程 - VirtualThread源码...
    99+
    2024-04-02
  • 【Java】JDK 21中的虚拟线程以及其他新特性
      目录 一、字符串模板(String Templates) 二、序列化集合(Sequenced Collections) 三、分代ZGC(Generational ZGC) 四、记录模式(Record Patterns) 五、Fibers...
    99+
    2023-10-25
    java 开发语言 intellij-idea
  • 解析Go语言的单线程特性
    Go语言的单线程特性解析 在Go语言中,虽然我们可以使用goroutine实现并发,但在实际执行时,Go程序仍然是单线程运行的。这种看似矛盾的现象主要得益于Go语言内建的调度器(sch...
    99+
    2024-04-02
  • JDK 21预告:虚拟线程正式发布及十多项新特性
    1 前言 Java 21进入发布候选阶段,其中包括15个最终特性,包括虚拟线程、分代Z垃圾收集器和密钥封装机制API。 JDK21计划于9月19日作为Oracle标准Java实现的下一个LTS版本发布...
    99+
    2023-09-22
    java jvm 开发语言 原力计划
  • HTML5新特性中多线程的示例分析
    这篇文章给大家分享的是有关HTML5新特性中多线程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、Worker类  1、方法介绍  (1)构造函数 new Worke...
    99+
    2024-04-02
  • Golang中协程与线程的特性和差异分析
    Golang中协程和线程的特点与区别分析 一. 引言Golang是一门现代化的编程语言,以其简洁、高效和并发性而闻名。在Golang中,协程和线程是实现并发编程的两种主要方式。本文将分析协程和线程的特点与区别...
    99+
    2024-01-24
    Golang 线程 协程
  • 怎么在虚拟主机中设置域名解析
    本篇文章给大家分享的是有关怎么在虚拟主机中设置域名解析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。进入虚拟主机云服务提供商网站;登录会员,进入会员中心;选择虚拟主机管理,找到...
    99+
    2023-06-14
  • 如何解析Java线程池在使用中的问题
    本篇文章为大家展示了如何解析Java线程池在使用中的问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java线程池需要我们不断的学习,其实我们在使用的时候还是有不少问题需要我们解决。我们实现了一个...
    99+
    2023-06-17
  • java 对象实例化过程中的多态特性解析
    目录java 对象实例化过程中的多态特性通过案例说明通过上述代码java对象的三个特性(封装、继承、多态)1.封装2.继承3.多态java 对象实例化过程中的多态特性 执行对象实例化...
    99+
    2024-04-02
  • 怎么在Java中利用网络编程模拟在线聊天
    本篇文章为大家展示了怎么在Java中利用网络编程模拟在线聊天,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1、前提知识需要知道简单的IO流操作,以及简单的UDP发送数据包的原理。需要用到的类:Dat...
    99+
    2023-06-15
  • 如何用XGBoost在Python 中进行特征重要性分析和特征选择
    如何用XGBoost在Python 中进行特征重要性分析和特征选择,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。使用诸如梯度增强之类的决策树方法的集成的好处是,...
    99+
    2023-06-15
  • 解决问题:VMware Tools 启动脚本未能在虚拟机中成功运行。
    目录 问题 解决 方法一、重装 open-vm-tools-desktop 方法二、重装 vmware-tools 问题 Ubuntu 虚拟机开机时提示报错,具体信息如下: VMware Tools 启动脚本未能在虚拟机中成功运行...
    99+
    2023-08-31
    linux ubuntu 运维 服务器
  • C++ 虚拟函数在性能优化中的作用:揭秘程序加速的秘诀
    虚拟函数在性能优化中的作用:动态绑定:支持多态性,允许父类指针调用子类方法。虚函数表 (vmt):存储所有类虚函数地址的表,减少额外的运行时查找。性能提升:编译器利用 vmt 优化虚拟函...
    99+
    2024-04-28
    性能优化 虚拟函数 c++
  • 怎么在Java中利用多线程模拟站点售票
    怎么在Java中利用多线程模拟站点售票?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、实验题目二、分析哦吼,这次的实验题目是一道非常经典的多线程买票问题。题目要求我们创建...
    99+
    2023-06-15
  • VMwareTools启动脚本未能在虚拟机中成功运行的两种解决方法
    目录问题解决方法一、重装 open-vm-tools-desktop方法二、重装 vmware-tools问题 Ubuntu 虚拟机开机时提示报错,具体信息如下: VMwa...
    99+
    2022-12-24
    VMware Tools 启动脚本未能在虚拟机运行 VMware Tools 虚拟机运行
  • 如何分析Python多线程在爬虫中的应用
    本篇文章为大家展示了如何分析Python多线程在爬虫中的应用,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。作为测试工程师经常需要解决测试数据来源的问题,解决思路无非是三种:直接从生产环境拷贝真实数据...
    99+
    2023-06-04
  • 在java项目中使用线程池如何实现获取运行线程数并控制线程启动速度
    这期内容当中小编将会给大家带来有关在java项目中使用线程池如何实现获取运行线程数并控制线程启动速度,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在java里, 我们可以使用Executors.newFi...
    99+
    2023-05-31
    java 线程池 线程
  • 深入解析C++中多态性和虚函数使用原理
    目录1.为什么需要virtual2.纯虚函数和抽象类3.构造函数与虚函数4.虚析构函数与纯虚析构函数5.纯虚析构函数的应用1.为什么需要virtual 按照Java的思维方式,在有了...
    99+
    2023-05-20
    C++ 多态性虚函数 C++ 多态性 C++ 虚函数
  • 多线程如何在C++性能优化中发挥作用?
    多线程提升 c++++ 性能的原理是允许多个线程同时执行,充分利用多核处理器。多线程创建多个执行流,每个线程有自己的调用栈和局部变量。线程通过共享内存通信,使用同步机制避免数据竞争。例如...
    99+
    2024-05-09
    c++ 多线程 性能优化 同步机制
  • 解析Golang在微服务架构中的适用性
    Golang在微服务架构中的应用场景解析 随着微服务架构的广泛应用,开发者们对于选择最合适的编程语言来构建微服务变得更加重要。Golang (Go语言)由Google开发,成为了不少开发者心目中的首选语言之一...
    99+
    2024-01-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作