You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache HttpAsyncClient回调中二次请求阻塞问题求助

为什么Apache HttpAsyncClient回调中发起二次请求会阻塞?

你的代码出现阻塞的核心原因是回调线程被阻塞,导致I/O线程池无法处理新请求,具体细节:

  • HttpAsyncClient的completed、failed这类回调方法,默认是在客户端的I/O线程中执行的,不是独立的业务线程。
  • 默认的HttpAsyncClient I/O线程池大小等于CPU核心数(比如单核心机器上只有1个I/O线程)。
  • 当你在completed里调用future1.get()时,会直接阻塞当前的I/O线程;而第二个请求的发送、响应处理都需要依赖I/O线程,此时唯一的I/O线程被卡住,无法处理新请求,形成死锁,代码自然一直停在get()这里。

解决方案1:用异步回调替代阻塞等待

既然是异步客户端,就延续异步的处理方式,不要在回调里同步等待结果,改用新的FutureCallback处理第二个请求:

package com.example.http;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.util.EntityUtils;

public class AsyncClientHttpExample {
    public static void main(String[] args) {
        CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
        httpClient.start();

        final HttpGet request1 = new HttpGet("http://httpbin.org/ip");

        httpClient.execute(request1, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(HttpResponse result) {
                try {
                    System.out.println(EntityUtils.toString(result.getEntity()));

                    final HttpGet anotherRequest = new HttpGet("http://httpbin.org/headers");
                    // 改用异步回调处理第二个请求,不阻塞当前线程
                    httpClient.execute(anotherRequest, new FutureCallback<HttpResponse>() {
                        @Override
                        public void completed(HttpResponse anotherResult) {
                            try {
                                System.out.println("response 1 " + EntityUtils.toString(anotherResult.getEntity()));
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        }

                        @Override
                        public void failed(Exception ex) {
                            System.out.println("第二个请求失败:" + ex);
                        }

                        @Override
                        public void cancelled() {
                            System.out.println("第二个请求被取消");
                        }
                    });

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void failed(Exception ex) {
                System.out.println(ex);
            }

            @Override
            public void cancelled() {

            }
        });
    }
}

解决方案2:配置独立的回调线程池

如果一定要在回调里做同步等待,可以给HttpAsyncClient配置专门的回调线程池,让回调在业务线程中执行,避免阻塞I/O线程:

package com.example.http;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.util.EntityUtils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AsyncClientHttpExample {
    public static void main(String[] args) {
        // 创建独立的回调线程池
        ExecutorService callbackExecutor = Executors.newFixedThreadPool(4);

        CloseableHttpAsyncClient httpClient = HttpAsyncClientBuilder.create()
                .setDefaultCallbackExecutor(callbackExecutor) // 指定回调执行的线程池
                .build();
        httpClient.start();

        final HttpGet request1 = new HttpGet("http://httpbin.org/ip");

        httpClient.execute(request1, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(HttpResponse result) {
                try {
                    System.out.println(EntityUtils.toString(result.getEntity()));

                    final HttpGet anotherRequest = new HttpGet("http://httpbin.org/headers");

                    Future<HttpResponse> future1 = httpClient.execute(anotherRequest, null);
                    HttpResponse anotherResponse = future1.get(); // 现在阻塞的是回调线程池的线程,不会影响I/O线程

                    System.out.println("response 1 " + EntityUtils.toString(anotherResponse.getEntity()));

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void failed(Exception ex) {
                System.out.println(ex);
            }

            @Override
            public void cancelled() {

            }
        });
    }
}

内容的提问来源于stack exchange,提问作者Jerry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:30:57