繁体   English   中英

如何在多线程操作中使用HttpAsyncClient?

[英]How to use HttpAsyncClient with multithreaded operation?

与这个问题密切相关: 如何在多线程操作中使用HttpClient? ,我想知道apache HttpAsyncClient是否是线程安全的,或者是否也需要使用MultiThreadedHttpConnectionManager或ThreadSafeClientConnManager。

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

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

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

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

谢谢。

您提到“跨会话独立”。 如果这仅表示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();
    }
}

在使用和不使用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
      }
    });
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM