1

我正在使用 Java 11 的内置 HTTP 客户端,但遇到了一个奇怪的问题,即客户端没有释放线程。我有以下代码:

public static void main(String[] args) throws InterruptedException, IOException, URISyntaxException {
    HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
    HttpResponse<Void> response;

    HttpRequest request = HttpRequest.newBuilder().uri(new URI("http://127.0.0.1:4321")).headers("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString("{}")).build();

    response = client.send(request, HttpResponse.BodyHandlers.discarding());
}

我正在使用 Maven 的 exec 插件运行应用程序,但出现以下错误:

[WARNING] thread Thread[HttpClient-1-Worker-0,5,com.example.httpclient.App] was interrupted but is still alive after waiting at least 14995msecs
[WARNING] thread Thread[HttpClient-1-Worker-0,5,com.example.httpclient.App] will linger despite being asked to die via interruption
[WARNING] thread Thread[HttpClient-1-Worker-1,5,com.example.httpclient.App] will linger despite being asked to die via interruption
[WARNING] thread Thread[HttpClient-1-Worker-2,5,com.example.httpclient.App] will linger despite being asked to die via interruption
[WARNING] NOTE: 3 thread(s) did not finish despite being asked to  via interruption. This is not a problem with exec:java, it is a problem with the running code. Although not serious, it should be remedied.
[WARNING] Couldn't destroy threadgroup org.codehaus.mojo.exec.ExecJavaMojo$IsolatedThreadGroup[name=com.example.httpclient.App,maxpri=10]

似乎客户端没有正确释放其线程。有趣的是,如果我注释掉发送请求的代码(同时保留创建客户端的代码),那么上述警告就会消失。

如果我System.exit(0)在最后添加,那么警告也会消失,但我仍然想知道为什么内置客户端会发生这种情况?客户端、请求或响应上没有关闭方法,所以我认为我没有泄漏资源。

我什至将客户端设置为 null 并手动调用 GC,即使问题仍然存在。很迷茫到底怎么回事。

4

1 回答 1

0

使用HttpClient带有守护线程的内部线程池。似乎客户端在垃圾收集时没有明确关闭此线程池。

您看到的警告与您的 Maven 插件部署的基础设施有关。似乎其他人也遇到过类似的问题(例如,请参阅无法破坏线程组 org.codehaus.mojo.exec.ExecJavaMojo$IsolatedThreadGroup[name=SitemapCheck.SitemapAction,maxpri=10])。

抑制警告的一种可能的解决方法是向Executor,并在您的 main 方法中HttpClient.Builder关闭它。Executor

请参阅https://docs.oracle.com/en/java/javase/15/docs/api/java.net.http/java/net/http/HttpClient.Builder.html#executor(java.util.concurrent.Executor )

作为记录,如果没有向 提供执行程序HttpClient.Builder,则HttpClient使用E​​xecutors.newCachedThreadPool(ThreadFactory)返回的执行程序。

于 2020-12-17T10:27:41.523 回答