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

2022-08-31 11:10:55

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

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

http://www.opensubscriber.com/message/commons-httpclient-dev@jakarta.apache.org/86045.html

因此,不是每个线程都执行:

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();
}

在正常情况下,50++ 个线程将同时访问global_c。我想知道,这会产生任何性能问题吗?MultiThreadedHttpConnectionManager是否使用无锁机制来实现其线程安全策略?

如果有 10 个线程正在使用global_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() 是否会遇到性能问题?

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


答案 1

绝对是方法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);

答案 2

方法 A 由 httpclient 开发人员社区推荐。

有关更多详细信息,请参阅 http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html


推荐