web-dev-qa-db-ja.com

マルチスレッド環境でHttpClientを使用するためのベストプラクティス

しばらくの間、マルチスレッド環境で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)の方が良いか知っていますか?

82
Cheok Yan Cheng

メソッドAは、httpclient開発者コミュニティによって推奨されています。

詳細については http://www.mail-archive.com/[email protected]/msg02455.html を参照してください。

17
Cheok Yan Cheng

プールされ、スレッドセーフであるため、確実にメソッド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);
43
user308808

私のドキュメントを読むと、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自体は開いたままになっていることに注意してください。

13
djna

ThreadSafeClientConnManagerを使用したいと思うと思います。

ここで動作を確認できます: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-Android.html

または、内部的に使用するAndroidHttpClientで。

5
Thomas Ahle

HttpClient 4.5を使用すると、次のことができます。

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

これはCloseableを実装していることに注意してください(接続マネージャーのシャットダウン用)。

2
Dimitar II