JDK11 的新 HTTP client API 搭配线程池把我的电脑搞挂了

2021-09-10 11:06:39 +08:00
 joyhub2140

1.创建线程池

final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);

2.创建 http 请求

var builder = HttpRequest.newBuilder()
                .uri(URI.create(uri));
HttpRequest request =
                    builder.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)).build();
//发送请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

3.创建任务,丢给线程池

List<CompletableFuture<?>> futures = new ArrayList<>();
        for (User user : Users) {
            CompletableFuture<?> future = CompletableFuture.runAsync(() -> {
                  用上面的 http 请求
            }, threadPoolExecutor);

            futures.add(future);
        }

        //等待所有任务完成
        final int taskCount = futures.size();
        CompletableFuture<?> allFuture = CompletableFuture.allOf((futures.toArray(new CompletableFuture[taskCount])));
        allFuture.join();

        //关闭线程池
        threadPoolExecutor.shutdown();

4.User 数是 2000 多,也就是任务数才 2000 多,就把我系统资源爆了,提示不能再继续创建 thread 了,我的 macOS 直接黑屏重启

我寻思我创建的线程池才 5 个,不至于让我的系统挂了吧?那元凶可能是 http 新的 client api 自己再私自创建大量线程,直到耗尽系统的线程资源数?有无大佬指教一下怎么优化?我就想我请求只限制在 5 个线程以内

3747 次点击
所在节点    Java
15 条回复
buster
2021-09-10 11:19:10 +08:00
HttpRequest 看下有没有资源需要释放,close 之类的?
nutting
2021-09-10 11:31:28 +08:00
这么多 http 请求很多了
joyhub2140
2021-09-10 11:34:13 +08:00
@nutting 线程池才给 5 条线程做请求哦。
yazinnnn
2021-09-10 11:34:40 +08:00
val client: HttpClient = HttpClient.newBuilder().executor(threadPoolExecutor).build()

用这个试试?

client.sendAsync()

发送请求用 HttpClient 的异步 api
securityCoding
2021-09-10 11:36:51 +08:00
你给的信息太少,不知道你的代码具体结构怎么组织的,提供几个思路
1. client 可以复用(an HttpClient is immutable, and can be used to send multiple requests.)
2. 线程池复用,为什么要在方法内关闭呢?
3. allFuture.join()是否应该改成 allFuture.get()
123zouwen
2021-09-10 11:38:56 +08:00
用之前至少先翻看一下 api 和源码吧

构建 HttpClient 的时候可以传入 Executor,查看源码没有传入会有一个默认的 Executors.newCachedThreadPool(new DefaultThreadFactory(id)

而且 jdk11 新的 HTTP client API 本身就可以发异步请求返回 CompletableFuture
一个 java11 httpclient 例子你简单看一下,
https://github.com/app2smile/java11-HttpClient-Util/blob/main/JdkHttpClientUtil.java
ForkNMB
2021-09-10 11:42:17 +08:00
首先,不建议使用 Executors.newFixedThreadPool 创建线程池,阻塞队列大小是没有大小限制的,如果队列堆积数据太多会造成资源消耗,手动指定一下线程池参数吧。
securityCoding
2021-09-10 11:43:02 +08:00
@123zouwen 看了一下源码,你是对的
wellsc
2021-09-10 12:02:09 +08:00
hhh
ikas
2021-09-10 13:20:19 +08:00
1.你这个 httpclient 根本就没有用你配置的 threadPoolExecutor ....
你只是自己写了一个异步
,CompletableFuture.runAsync(() -> {
用上面的 http 请求
}, threadPoolExecutor);
,你应该直接用 httpclient 内置的 async 方法,同时给其配置线程池

2.你这么多请求全部等待...内存肯定耗尽了..所以 httpclient 内部也没有办法创建进程了..
3.内存崩了系统挂了..那么应该是系统问题....
BBCCBB
2021-09-10 14:10:47 +08:00
所以看起来是 sendAsync 的时候用的默认的 CachedThreadPool() 导致的创建了太多线程?

这个线程看起来是异步执行完后的回调线程.

是 completeAsync(() -> null, executor) 导致的?
DonaldY
2021-09-10 14:22:28 +08:00
httpClient 线程池 没设置
dqzcwxb
2021-09-10 14:42:00 +08:00
啥也不知道就让别人改线程池参数是最搞笑的,说一句正确的废话
dqzcwxb
2021-09-10 14:48:35 +08:00

HttpClientImpl.java:277
贴上源码地址方便后来人
guyeu
2021-09-11 10:45:50 +08:00
题外话,旧版本的 HttpClient 确实有连接泄露的 bug,想在生产环境中用最好升级

https://bugs.openjdk.java.net/browse/JDK-8241810

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/801001

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX