jdk11的HttpClient关闭?

HTTP Client API在Java 9被引入,在Java 10进行了更新,不过一直处于孵化状态,在此次Java 11中获得正式发布,包名由jdk.incubator.http改为java.net.http。HTTP Client API实现了HTTP(1.1和2)和WebSocket,用来取代遗留的java.net.HttpURLConnection。该API用来在Java程序中作为客户端请求HTTP服务,Java中服务端HTTP的支持由Servlet实现。

最近发现tomcat关闭的时候会给出如下警告:

The web application [ROOT] appears to have started a thread named [HttpClient-1-SelectorManager] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 java.base@11/sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
 java.base@11/sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:339)
 java.base@11/sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:167)
 java.base@11/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:124)
 java.base@11/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:136)
 platform/java.net.http@11/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:867)

看了源码后发现是HttpClient的实现里启动了一个名为HttpClient-${clientId}-SelectorManager的守护线程,但是HttpClient本身并没有提供任何关闭方法,因此无法直接关闭。

看了下SelectorManager的run方法,简化如下:

@Override
public void run() {
   try {
       while (!Thread.currentThread().isInterrupted()) {
           synchronized (this) {
               if (!owner.isReferenced()) {
                   return;
               }
           }
       }
   } finally {
       shutdown();
   }
}

也就是说只有在线程本身被打断或者HttpClient对象不再被引用时才会调用shutdown方法,所以如果需要关闭HttpClient,直接设置HttpClient的引用为null,等垃圾回收之后就会关闭,或者干脆打断这个线程:

HttpClient client = HttpClient.newHttpClient();
String toStr = client.toString();
String id = toStr.substring(toStr.lastIndexOf('(') + 1, toStr.length() - 1);
String threadName = "HttpClient-" + id + "-SelectorManager";
Thread.getAllStackTraces().keySet().stream().filter(t -> t.getName().equals(threadName)).findFirst()
       .ifPresent(Thread::interrupt);

如果仅仅是为了tomcat的警告,那么直接打断线程才能满足要求,直接打断线程无法保证正在执行的异步操作能执行完毕

最后,我们真的需要为了一个无关紧要的警告大费周章的写出如此丑陋的代码吗?

 

上一篇:java关闭Process