Java 11添加了HttpClient,为我们提供了一种更好的HTTP请求发送方式。它支持异步和同步模式。支持HTTP2开箱即用。有点时髦,Cay Horstmann教授探讨了如何在表面下的工作原理。
在 JCrete 2019年 ,Heinz Kabutz主持了一个演讲,展示了为HttpClient该类配置线程池的谜团。设置新的执行程序没有达到预期的效果。事实证明,实施已经发生了变化(也许并没有变得更好),而且文档也是滞后的。如果您计划HttpClient异步使用,您真的要注意这一点。
HttpClient Executors
HttpClient是Java 9中的孵化器功能,最终成为Java 11中Java API的一部分。它提供了比经典HttpURLConnection类更令人愉快的API ,具有良好的异步接口,并且可以使用HTTP / 2。本文讨论异步接口。
假设你想要阅读一个网页,然后一旦它访问到就处理它。首先做一个HttpClient对象:
HttpClient client = HttpClient.newBuilder() <font><i>// Redirect except https to http</i></font><font> .followRedirects(HttpClient.Redirect.NORMAL) .build(); </font>
然后执行一个请求:
HttpRequest request = HttpRequest.newBuilder() .uri(<b>new</b> URI(<font>"http://horstmann.com"</font><font>)) .GET() .build(); </font>
现在获取响应并处理它,添加sendAsync方法返回的未来可完成(completable future)的结果:
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenAccept(response -> ...);
sendAsync方法使用非阻塞I / O来获取数据。当数据可用时,数据将被传递给回调函数立即进行处理。HttpClient使用标准的 CompletableFuture接口。传递给thenAccept的回调函数在数据准备好时调用。
在哪个线程?当然不是在调用的线程中 client.sendAsync。因为这个线程已经开始做其他事情。
HttpClient.Builder类里有一个方法 executor:
ExecutorService executor1 = Executors.newCachedThreadPool(); HttpClient client = HttpClient.newBuilder() .executor(executor1) .followRedirects(HttpClient.Redirect.NORMAL) .build();
根据JDK 11文档,这“将executor 执行器设置为用于异步和依赖任务”。
Heinz的图像采集者之谜
在JCrete 2019年,Heinz Kabutz演示了一个程序,它抓住当天的Dilbert漫画,转到表格的URL https://dilbert.com/strip/2019-08-21,找到里面的图像URL,然后加载图像。
但它没有用。在我的Linux笔记本电脑上,该程序刚挂起,而在Heinz的Mac上,它在尝试获取10,000张图像时因内存不足而崩溃。
Executor
Heinz并不是第一个注意到设置执行程序不能按预期工作的人 - 看到 这个StackOverflow查询 。这是自JDK 11以来的 行为变化 。现在,“依赖”任务 不是 由提供的执行程序执行,而是由公共fork-join池执行。但是,文档尚未更新以跟踪更改,这是 另一个错误 。
让我们从变更通知中挑选重点的陈述:
<b>return</b> client.sendAsync(request, responseBodyHandler) .thenApplyAsync(HttpResponse::body, executor2);
以下是要点:
HttpClient实现使用缓存线程池cached thread pool 来完成其任务。在Linux上,当获取10,000个图像时,HttpClient executor 永远不会有超过几百个并发任务,在Mac上,虚拟机在创建超过2,000个线程后内存不足,当提供固定的线程池 fixed thread pool时,程序挂在Mac上,就像在Linux上一样。
当进行 completable futures链式调用时,确保处理异常,尤其是在您需要管理计数器或资源时。
点击标题见原文详细分析