前提趁着国庆前后阅读了虚拟线程相关的源码,写了一篇《虚拟线程 - VirtualThread源码透视》,里面介绍了虚拟线程的实现原理和使用示例 。需要准备做一下前期准备:
- 安装OpenJDK-19或者Oracle JDK-19
- 准备好嵌入式Tomcat的依赖,需要引入三个依赖包,分别是tomcat-embed-core、tomcat-embed-el和tomcat-embed-websocket,版本选用10.1.0+
文章插图
支持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"; }}
经验总结扩展阅读
- 三峡中最长的峡是什么
- Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?
- 便秘有哪些表现
- 兔子吃什么长肉
- 中级调酒师要考什么
- 如何区分过敏和感冒
- 泰山在哪个省哪个市
- 使用电暖器注意哪些事项
- 光遇欧若拉季神龛位置在哪
- 大人缺钙的怎么补钙