Java 在多线程环境中使用HttpClient的最佳实践

Java 在多线程环境中使用HttpClient的最佳实践,java,apache-commons-httpclient,Java,Apache Commons Httpclient,有一段时间,我一直在多线程环境中使用HttpClient。对于每个线程,当它启动连接时,它将创建一个全新的HttpClient实例 最近,我发现,通过使用这种方法,可能会导致用户打开太多端口,并且大多数连接都处于TIME\u WAIT状态 因此,不是每个线程都执行以下操作: HttpClient c = new HttpClient(); try { c.executeMethod(method); } catch(...) { } finally { method.relea

有一段时间,我一直在多线程环境中使用HttpClient。对于每个线程,当它启动连接时,它将创建一个全新的HttpClient实例

最近,我发现,通过使用这种方法,可能会导致用户打开太多端口,并且大多数连接都处于TIME\u WAIT状态

因此,不是每个线程都执行以下操作:

HttpClient c = new HttpClient();
try {
    c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}
我们计划:

[方法A]

// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());

try {
    global_c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}
在正常情况下,全局_c将由50++线程并发访问。我想知道,这会不会造成性能问题?多线程HttpConnectionManager是否使用无锁机制来实现其线程安全策略

如果10个线程正在使用全局_c,那么其他40个线程是否会被锁定

或者,如果在每个线程中创建一个HttpClient实例,但显式地释放连接管理器,会更好吗

[方法B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
      c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
    connman.shutdown();
}
connman.shutdown()是否会遇到性能问题


对于使用50++线程的应用程序,我可以知道哪种方法(A或B)更好吗?

我对文档的理解是,HttpConnection本身并不是线程安全的,因此多线程HttpConnectionManager提供了一个可重用的HttpConnections池,您有一个由所有线程共享的多线程HttpConnectionManager,并且只初始化了一次。因此,您需要对选项a进行一些小的改进

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag
然后,每个线程应该为每个请求使用序列,从池中获取连接,并在完成其工作时将其放回——使用finally块可能会更好。 您还应该编码池没有可用连接的可能性,并处理超时异常

HttpConnection connection = null
try {
    connection = connman.getConnectionWithTimeout(
                        HostConfiguration hostConfiguration, long timeout) 
    // work
} catch (/*etc*/) {/*etc*/} finally{
    if ( connection != null )
        connman.releaseConnection(connection);
}

由于您使用的是一个连接池,因此实际上不会关闭连接,因此这不会影响时间等待问题。这种方法假设每个线程不会长时间挂起连接。请注意,conman本身是开放的。

方法A是httpclient开发者社区推荐的


有关更多详细信息,请参阅。

我认为您将希望使用ThreadSafeClientConnManager

您可以在此处看到它的工作原理:


或者在内部使用它的
AndroidHttpClient
中。

肯定是方法A,因为它是池和线程安全的

如果您使用的是httpclient 4.x,则连接管理器称为ThreadSafeClientConnManager。有关更多详细信息,请参见此页(向下滚动至“池连接管理器”)。例如:

    HttpParams params = new BasicHttpParams();
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
    HttpClient client = new DefaultHttpClient(cm, params);

使用HttpClient 4.5,您可以执行以下操作:

CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();

请注意,此方法实现了Closeable(用于关闭连接管理器)。

没有实际回答我的问题,哪种方法(A或B)更好。Opps。没有从HttpClient 3.x迁移到4.x的计划,因为3.x在我的应用程序中已经运行了将近2年了:)当然,如果有人来这里用谷歌搜索答案:)已经被弃用,取而代之的是4.2Hi,那么用这个方法创建的HttpClient可以用来维护这里描述的会话吗。。。?因为当我尝试时,我无法跨不同的请求维护会话…这里是4.3.1:PoolgClientConnectionManager已被弃用,取而代之的是PoolghtClientConnectionManager。@DrewStephens PoolgClientConnectionManager再次被弃用,取而代之的是PoolghtClientConnectionManager何时会调用“shutdown”在连接管理器上,如果客户端是全局的。哪些工具/linux命令对于调试或“可视化”连接管理器的行为非常有用?我问这个问题是因为我们目前在CLOSE_WAIT和其他效果中的连接有问题,我们正在寻找一种好方法来了解到底发生了什么。@WandMaker我很确定,当程序退出或当您完成了一些工作时,您只需呼叫关机,而这些工作在某些情况下不需要任何连接时间。@Christoph
netstat
在这方面做得非常好。也