5

与这个问题密切相关:How to use HttpClient with multithreaded operation?,我想知道 apache HttpAsyncClient 是否是线程安全的,或者它是否也需要使用 MultiThreadedHttpConnectionManager 或 ThreadSafeClientConnManager。

如果确实需要这样的连接管理器,异步库中是否存在?

我能够在异步库中找到 PoolingClientAsyncConnectionManager,但我不确定这是否是我需要的。

或者,我正在考虑使用 ThreadLocal 为每个线程创建一个 HttpAsyncClient 对象。

请注意,与我之前提到的问题不同,我需要状态在会话之间是独立的,即使多个会话访问同一个域也是如此。如果在会话 1 中设置了 cookie,则 cookie对会话 2可见。出于这个原因,我还考虑为每个请求创建一个全新的 HttpAsyncClient 对象,尽管我觉得应该有更好的方法.

谢谢。

4

2 回答 2

2

您提到“跨会话独立”。如果这只是意味着cookie,那么我会认为创建自己的cookie CookieStore,当您的每个线程使用时清除HttpClient它就足够了。

我会使用ThreadLocal创建一个每线程客户端,不使用共享连接管理器,然后积极清除 cookie。这个答案对清除 cookie 很有用:

Android HttpClient 持久性 cookie

类似以下代码的东西会起作用。如果每个请求都是独立的,我已经覆盖了ThreadLocal.get()要调用的方法。clear()您也可以在execute(...)方法中调用 clear 。

private static final ThreadLocal<ClientContext> localHttpContext = 
    new ThreadLocal<ClientContext> () {
        @Override
        protected ClientContext initialValue() {
           return new ClientContext();
        }
        @Override
        public ClientContext get() {
           ClientContext clientContext = super.get();
           // could do this to clear the context before usage by the thread
           clientContext.clear();
           return clientContext;
        }
    };
...

ClientContext clientContext = localHttpContext.get();
// if this wasn't in the get method above
// clientContext.clear();
HttpGet httpGet = new HttpGet("http://www.google.com/");
HttpResponse response = clientContext.execute(httpGet);
...

private static class ClientContext {
    final HttpClient httpClient = new DefaultHttpClient();
    final CookieStore cookieStore = new BasicCookieStore();
    final HttpContext localContext = new BasicHttpContext();
    public ClientContext() {
         // bind cookie store to the local context
         localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    }
    public HttpResponse execute(HttpUriRequest request) {
         // in case you want each execute to be indepedent
         // clientContext.clear();
         return httpClient.execute(request, httpContext);
    }
    public void clear() {
         cookieStore.clear();
    }
}
于 2012-08-14T19:29:28.697 回答
1

在使用和不使用 PoolingClientAsyncConnectionManager 进行负载测试后,我们发现在不使用 PoolingClientAsyncConnectionManager 时得到的结果不一致。

除其他外,我们跟踪了我们进行的 Http 调用的数量,以及已完成的 Http 调用的数量(通过 cancelled(...)、completed(...) 或 failed(...) 函数)相关的 FutureCallback)。如果没有 PoolingClientAsyncConnectionManager,并且在重负载下,这两个数字有时不匹配,这使我们相信在某个地方,某些连接正在踩踏来自其他线程的连接信息(只是猜测)。

无论哪种方式,使用 PoolingClientAsyncConnectionManager,数字总是匹配的,并且负载测试都成功了,所以我们肯定会使用它。

我们使用的最终代码如下所示:

public class RequestProcessor {
  private RequestProcessor instance = new RequestProcessor();
  private PoolingClientAsyncConnectionManager pcm = null;
  private HttpAsyncClient httpAsyncClient = null;
  private RequestProcessor() {
    // Initialize the PoolingClientAsyncConnectionManager, and the HttpAsyncClient 
  }
  public void process(...) {
    this.httpAsyncClient.execute(httpMethod, 
         new BasicHttpContext(), // Use a separate HttpContext for each request so information is not shared between requests
         new FutureCallback<HttpResponse>() {
      @Override
      public void cancelled() {
        // Do stuff
      }
      @Override
      public void completed(HttpResponse httpResponse) {
        // Do stuff
      }
      @Override
      public void failed(Exception e) {
        // Do stuff
      }
    });
  }
}
于 2012-11-10T05:58:59.553 回答