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

能否使用单个PoolingNHttpClientConnectionManager运行多个HttpAsyncClient?

问题:多个HttpAsyncClient共用连接管理器启动报错

尝试创建多个CloseableHttpAsyncClient实例并共用同一个PoolingNHttpClientConnectionManager时,运行出现以下错误:

14:00:56.443 [pool-2-thread-1] ERROR org.apache.http.impl.nio.client.InternalHttpAsyncClient - I/O reactor terminated abnormally
java.lang.IllegalStateException: Illegal state ACTIVE
    at org.apache.http.util.Asserts.check(Asserts.java:46)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:316)
    at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:221)
    at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64)
    at java.base/java.lang.Thread.run(Thread.java:833)

Exception in thread "main" java.util.concurrent.ExecutionException: java.util.concurrent.CancellationException: Request execution cancelled
    at org.apache.http.concurrent.BasicFuture.getResult(BasicFuture.java:71)
    at org.apache.http.concurrent.BasicFuture.get(BasicFuture.java:84)
    at org.apache.http.impl.nio.client.FutureWrapper.get(FutureWrapper.java:70)
    at com.example.Test.main(Test.java:32)
Caused by: java.util.concurrent.CancellationException: Request execution cancelled
    at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase.execute(CloseableHttpAsyncClientBase.java:114)
    at org.apache.http.impl.nio.client.InternalHttpAsyncClient.execute(InternalHttpAsyncClient.java:138)
    at org.apache.http.impl.nio.client.CloseableHttpAsyncClient.execute(CloseableHttpAsyncClient.java:75)
    at org.apache.http.impl.nio.client.CloseableHttpAsyncClient.execute(CloseableHttpAsyncClient.java:108)
    at org.apache.http.impl.nio.client.CloseableHttpAsyncClient.execute(CloseableHttpAsyncClient.java:92)
    at com.example.Test.main(Test.java:31)

问题原因

HttpAsyncClient启动时,会自动调用连接管理器的execute()方法启动关联的IOReactor。但同一个IOReactor只能处于ACTIVE状态一次,第一个客户端启动后,IOReactor已经运行,第二个客户端尝试再次启动就会触发IllegalStateException,导致客户端初始化失败,请求被取消。

解决方案

方案1:复用单个HttpAsyncClient实例

CloseableHttpAsyncClient本身是线程安全的,完全可以在多线程环境下复用同一个实例处理不同请求,这是最推荐的方式:

package com.example;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;

import java.util.concurrent.ExecutionException;

public class Test {
    public static void main(String[] args) throws IOReactorException, ExecutionException, InterruptedException {
        ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.custom().build());
        PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
        
        // 只创建一个客户端实例
        CloseableHttpAsyncClient client = HttpAsyncClientBuilder.create()
                .setConnectionManager(connManager)
                .setRedirectStrategy(new LaxRedirectStrategy())
                .build();
        client.start();

        // 用同一个客户端执行多个请求
        var res1 = client.execute(new HttpGet("https://www.google.com"), null);
        res1.get();
        var res2 = client.execute(new HttpGet("https://www.google.com"), null);
        res2.get();
        
        // 最后关闭客户端
        client.close();
    }
}

方案2:标记连接管理器为共享模式

如果必须创建多个客户端实例,需要在构建后续客户端时调用setConnectionManagerShared(true),告诉客户端不要启动连接管理器的IOReactor(由第一个客户端负责启动):

package com.example;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;

import java.util.concurrent.ExecutionException;

public class Test {
    public static void main(String[] args) throws IOReactorException, ExecutionException, InterruptedException {
        ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.custom().build());
        PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
        
        CloseableHttpAsyncClient client1 = HttpAsyncClientBuilder.create()
                .setConnectionManager(connManager)
                .setRedirectStrategy(new LaxRedirectStrategy())
                .build();
        client1.start();
        
        // 第二个客户端标记连接管理器为共享
        CloseableHttpAsyncClient client2 = HttpAsyncClientBuilder.create()
                .setConnectionManager(connManager)
                .setConnectionManagerShared(true)
                .build();
        client2.start();

        var res1 = client1.execute(new HttpGet("https://www.google.com"), null);
        res1.get();
        var res2 = client2.execute(new HttpGet("https://www.google.com"), null);
        res2.get();
        
        // 注意:关闭顺序,最后关闭的客户端会关闭连接管理器,若需继续使用其他客户端,需手动管理连接管理器生命周期
        client2.close();
        client1.close();
    }
}

注意事项

  • 使用共享连接管理器模式时,必须确保第一个客户端先启动,否则IOReactor未运行会导致请求失败。
  • 关闭客户端时,最后关闭的客户端会自动关闭连接管理器和IOReactor,如果还有其他客户端需要使用,不要关闭连接管理器,或者手动调用connManager.shutdown()来终止资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:08:11