web-dev-qa-db-ja.com

BasicClientConnManagerの無効な使用:接続はまだ割り当てられています

REST URLを呼び出して、応答を返すのにかかる時間を測定しようとしています。

REST URLから応答を取得するために、DefaultHttpClientを使用しています。

以下のプログラムでは、各スレッドは特定の範囲で動作します。各スレッドが1 - 100間で機能し、2番目のスレッドが101 - 200など間で機能するように.

以下のコードでは、初めて正常に動作します。しかし、2回目はhttpclient.executeとしてこの行に例外をスローしています。

Java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

ここで何か間違っていることはありますか?-

以下は私のコードです

class Task implements Runnable {

    private DefaultHttpClient httpclient = new DefaultHttpClient();
    private HttpGet httpGet;
    private HttpResponse response;

    @Override
    public void run() {

        try {

            httpGet = new HttpGet(
                    "http://localhost:8080/service/BEService/v1/get/USERID=10000/profile.ACCOUNT.SERVICE
            httpGet.getRequestLine();

            for (int userId = id; userId < id + noOfTasks; userId++) {

                    long start = System.nanoTime();

                    response = httpclient.execute(httpGet);

                    long end = System.nanoTime() - start;
                }
        } catch (Exception e) {
            LOG.error("Threw a Exception in " + getClass().getSimpleName(), e);
        }
    }
}

更新コード:-

このようなことをしているなら

class Task implements Runnable {

    private DefaultHttpClient httpclient = new DefaultHttpClient();
    private HttpGet httpGet;
    private HttpResponse response;

    @Override
    public void run() {

        try {

            for (int userId = id; userId < id + noOfTasks; userId++) {

                httpGet = new HttpGet("http://localhost:8080/service/BEService/v1/get/USERID=10000/profile.ACCOUNT.SERVICE");
                httpGet.getRequestLine();

                long start = System.nanoTime();

                response = httpclient.execute(httpGet);

                long end = System.nanoTime() - start;

                HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
                }
        } catch (Exception e) {
            LOG.error("Threw a Exception in " + getClass().getSimpleName(), e);
        }
    }
}

それでいいですか?

40
AKIWEB

ここで何か間違ったことはありますか?

はい。 ドキュメント に記載されているとおり:

BasicClientConnectionManagerは、一度に1つの接続のみを維持する単純な接続マネージャーです。このクラスはスレッドセーフですが、1つの実行スレッドのみが使用する必要があります。 BasicClientConnectionManagerは、同じルートを持つ後続のリクエストで接続を再利用するよう努力します。ただし、永続的な接続のルートが接続要求のルートと一致しない場合は、既存の接続を閉じて、指定されたルートに対して再度開きます。接続がすでに割り当てられている場合、Java.lang.IllegalStateExceptionがスローされます。

BasicClientConnectionManagerは、デフォルトでHttpClientによって使用されます。

"Multithreaded request execution" を使用して、複数のスレッド間でリクエストを処理できる pooling connection manager を参照してください。

44
Ryan Stewart

Vanilla DefaultHttpClient(内部でBasicClientConnectionManagerを使用)を使用していると仮定すると、最初に未解決/最後の応答を消費する必要があります。

EntityUtils.consumeQuietly(httpResponse.getEntity());

それ以外の場合は、DefaultHttpClientを毎回再割り当てできます。

ソース: 使用後に毎回DefaultHttpClient()をシャットダウンしないための回避策

40
kevinarpe

これは、プール接続マネージャーを使用したRestTemplateの私の構成です。さらに5つの並行スレッドで非常にうまく機能します。

<!-- RestTemplate -->
<beans:bean id="restTemplateYT" class="org.springframework.web.client.RestTemplate">
    <beans:constructor-arg ref="httpRequestFactoryYT" />
</beans:bean>

<beans:bean id="httpRequestFactoryYT" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"> 
    <beans:constructor-arg>
        <beans:bean class="org.Apache.http.impl.client.DefaultHttpClient">
            <beans:constructor-arg>
                <beans:bean class="org.Apache.http.impl.conn.PoolingClientConnectionManager"/>
            </beans:constructor-arg>
        </beans:bean>
    </beans:constructor-arg>
    <beans:property name="connectTimeout" value="5000" />
</beans:bean>

Springバージョン:3.1.0

1
Jerry Chen