しばらくの間、マルチスレッド環境で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();
}
私たちが持っている予定
[方法A]
// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());
try {
global_c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
}
通常の状況では、global_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()はパフォーマンスの問題に悩まされますか?
50 ++スレッドを使用するアプリケーションの場合、どちらの方法(AまたはB)の方が良いか知っていますか?
メソッドAは、httpclient開発者コミュニティによって推奨されています。
詳細については http://www.mail-archive.com/[email protected]/msg02455.html を参照してください。
プールされ、スレッドセーフであるため、確実にメソッドA。
Httpclient 4.xを使用している場合、接続マネージャーはThreadSafeClientConnManagerと呼ばれます。詳細は link をご覧ください(「プール接続マネージャー」までスクロールダウンしてください)。例えば:
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を実装していることに注意してください(接続マネージャーのシャットダウン用)。