Ответ 1
Метод A рекомендуется сообществом разработчиков httpclient.
Подробнее см. http://www.mail-archive.com/[email protected]/msg02455.html.
Некоторое время я использовал HttpClient в многопоточной среде. Для каждого потока, когда он инициирует соединение, он создаст совершенно новый экземпляр HttpClient.
Недавно я обнаружил, что с помощью этого подхода пользователь может открыть слишком много портов, и большинство подключений находятся в состоянии TIME_WAIT.
http://www.opensubscriber.com/message/[email protected]/86045.html
Следовательно, вместо каждого потока выполните:
HttpClient c = new HttpClient();
try {
c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
}
Мы планируем:
[МЕТОД А]
// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());
try {
global_c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
}
В нормальной ситуации глобальный_c будет доступен одновременно потоками 50 ++. Мне было интересно, это создаст какие-либо проблемы с производительностью? Является ли 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 ++?
Метод A рекомендуется сообществом разработчиков httpclient.
Подробнее см. http://www.mail-archive.com/[email protected]/msg02455.html.
Определенно метод А, потому что его объединенный и потокобезопасный.
Если вы используете 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);
Мое чтение документов заключается в том, что сам HttpConnection не рассматривается как потокобезопасный, и, следовательно, MultiThreadedHttpConnectionManager предоставляет многоразовый пул HttpConnections, у вас есть один MultiThreadedHttpConnectionManager, общий для всех потоков и инициализированный ровно один раз. Поэтому вам нужно несколько небольших уточнений в опции 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);
}
Поскольку вы используете пул соединений, вы фактически не закрываете соединения, и поэтому это не должно затрагивать проблему TIME_WAIT. Этот подход позволяет предположить, что каждый поток не поддерживает связь в течение долгого времени. Обратите внимание, что сам conman остается открытым.
Я думаю, вы захотите использовать ThreadSafeClientConnManager.
Вы можете увидеть, как он работает здесь: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html
Или в AndroidHttpClient
, который использует его внутри.
С помощью HttpClient 4.5 вы можете сделать это:
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
Обратите внимание, что этот инструмент реализует Closeable (для закрытия диспетчера соединений).