该Servlet实现比较简单,就是在控制台打印一些虚拟线程和载体线程的一些信息,然后返回HTTP状态码为200和一个JSON字符展示当前精确到毫秒的时间 。接着编写一个main方法初始化Tomcat:
public class EmbedTomcatVirtualThreadDemo { private static final String SERVLET_NAME = "VirtualThreadHandleServlet"; private static final String SERVLET_PATH = "/*"; /** * 设置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 * * @param args args * @throws Exception e */ 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方法启动后见控制台输出:
经验总结扩展阅读
- 三峡中最长的峡是什么
- Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?
- 便秘有哪些表现
- 兔子吃什么长肉
- 中级调酒师要考什么
- 如何区分过敏和感冒
- 泰山在哪个省哪个市
- 使用电暖器注意哪些事项
- 光遇欧若拉季神龛位置在哪
- 大人缺钙的怎么补钙