V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
joyhub2140
V2EX  ›  Java

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

  •  
  •   joyhub2140 · 2021-09-10 11:06:39 +08:00 · 3869 次点击
    这是一个创建于 1169 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 个线程以内

    第 1 条附言  ·  2021-09-10 11:49:26 +08:00

    谢谢大家,我传入一个单线程的池子给httpclient的builder就没问题了。

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

    用这个试试?

    client.sendAsync()

    发送请求用 HttpClient 的异步 api
    securityCoding
        5
    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
        6
    123zouwen  
       2021-09-10 11:38:56 +08:00   ❤️ 1
    用之前至少先翻看一下 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
        7
    ForkNMB  
       2021-09-10 11:42:17 +08:00
    首先,不建议使用 Executors.newFixedThreadPool 创建线程池,阻塞队列大小是没有大小限制的,如果队列堆积数据太多会造成资源消耗,手动指定一下线程池参数吧。
    securityCoding
        8
    securityCoding  
       2021-09-10 11:43:02 +08:00
    @123zouwen 看了一下源码,你是对的
    wellsc
        9
    wellsc  
       2021-09-10 12:02:09 +08:00
    hhh
    ikas
        10
    ikas  
       2021-09-10 13:20:19 +08:00
    1.你这个 httpclient 根本就没有用你配置的 threadPoolExecutor ....
    你只是自己写了一个异步
    ,CompletableFuture.runAsync(() -> {
    用上面的 http 请求
    }, threadPoolExecutor);
    ,你应该直接用 httpclient 内置的 async 方法,同时给其配置线程池

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

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

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

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

    https://bugs.openjdk.java.net/browse/JDK-8241810
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5361 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 03:36 · PVG 11:36 · LAX 19:36 · JFK 22:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.