使用HttpClient循环发送HttpRequest失败问题求助
解决HttpClient循环发送请求时后续请求阻塞的问题
嘿,这个问题我之前做接口压测的时候碰到过!大概率是你没处理好连接资源释放或者HttpClient实例复用的问题,咱们一步步来捋:
核心问题分析
你现在的代码每次循环都调用Launcher.bulider()来创建请求,很可能存在两个隐患:
- 没有释放响应资源:如果
fullResponse()返回的HttpResponse没有被正确关闭/消费实体,连接会被卡在占用状态,连接池很快就会被耗尽,后续请求拿不到可用连接,就会进入等待状态。 - 频繁新建HttpClient实例:HttpClient是重量级对象,自带连接池管理。每次循环新建实例会导致系统资源(线程、端口)被快速消耗,同样会引发阻塞。
具体解决方案
1. 复用HttpClient实例
HttpClient是线程安全的,应该全局只初始化一次,而不是每次请求都新建。你可以在Launcher里做一个单例的HttpClient,或者在循环外部创建好传入:
// 全局复用的HttpClient实例(只初始化一次) CloseableHttpClient httpClient = HttpClients.createDefault();
2. 强制释放响应资源
不管你要不要读取响应内容,都必须确保HttpResponse的实体被消费或者响应被关闭。用try-with-resources语法是最稳妥的方式:
for (int i = 0; i < 10; i++) { try (CloseableHttpResponse response = (CloseableHttpResponse) Launcher.bulider() .setHttpClient(httpClient) // 传入复用的HttpClient .setCharSet("utf-8") .setHttpMethod("GET") .setUrl("http://www.baidu.com") .fullResponse()) { // 处理你的响应逻辑 System.out.println("第" + (i+1) + "次请求,状态码:" + response.getStatusLine().getStatusCode()); // 强制消费实体,避免连接占用 EntityUtils.consume(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } } // 所有请求结束后,关闭HttpClient try { httpClient.close(); } catch (IOException e) { e.printStackTrace(); }
3. 检查Launcher的封装逻辑
如果你的Launcher工具类内部每次build都新建HttpClient,那一定要改成复用单例。比如在Launcher里加个静态的HttpClient实例:
public class Launcher { // 单例HttpClient private static final CloseableHttpClient HTTP_CLIENT = HttpClients.createDefault(); private Launcher() {} public static Launcher bulider() { return new Launcher(); } // ... 其他set方法 public CloseableHttpResponse fullResponse() throws IOException { // 使用全局的HTTP_CLIENT发送请求,而不是每次新建 HttpGet request = new HttpGet(this.url); // ... 设置其他请求参数 return HTTP_CLIENT.execute(request); } }
为什么会这样?
HttpClient的连接池默认是有数量限制的(比如maxTotal默认20,defaultMaxPerRoute默认2)。如果每次请求后不释放连接,连接会一直被挂着,很快池子里就没有可用连接了,后续请求只能阻塞等待连接被释放——这就是你看到线程处于等待状态的根本原因。
内容的提问来源于stack exchange,提问作者Zard Loo
相关产品推荐
相关产品推荐

