How to use HttpAsyncClient with multithreaded operation?

隐身守侯 提交于 2020-01-02 06:06:10

问题


Closely related to this question: How to use HttpClient with multithreaded operation?, I'm wondering if apache HttpAsyncClient is thread safe, or if it, too, requires the use of a MultiThreadedHttpConnectionManager, or a ThreadSafeClientConnManager.

If it does require such a connection manager, does one exist in the async libraries?

I was able to find a PoolingClientAsyncConnectionManager in the async libraries, but I'm not sure if that's what I need.

Alternately, I was thinking of using ThreadLocal to create one HttpAsyncClient object per thread.

Note that unlike the question I referenced earlier, I need state to be independent across sessions, even if multiple sessions hit the same domain. If a cookie is set in session 1, the cookie should not be visible to session 2. For this reason, I've also considered creating a brand new HttpAsyncClient object for every single request, though I get the impression there should be a better way.

Thanks.


回答1:


You mention "independent across sessions". If this just means cookies then I would think creating your own CookieStore which is cleared when each of your threads goes to use a HttpClient would be enough.

I would use ThreadLocal to create a per-thread client, don't use a shared connection manager, and then clear the cookies aggressively. This answer was useful around cookie clearing:

Android HttpClient persistent cookies

Something like the following code would work. I've overridden the ThreadLocal.get() method to call clear() in case each request is independent. You could also call clear in the execute(...) method.

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();
    }
}



回答2:


After load testing both with and without the PoolingClientAsyncConnectionManager, we discovered that we got inconsistent results when we did not use the PoolingClientAsyncConnectionManager.

Amongst other things, we tracked the number of Http calls we were making, and the number of Http calls that were completed (either through the cancelled(...), completed(...), or failed(...) functions of the associated FutureCallback). Without the PoolingClientAsyncConnectionManager, and under heavy load, the two figures sometimes did not match up, leading us to believe that somewhere, some connections were stomping on connection information from other threads (just a guess).

Either way, with the PoolingClientAsyncConnectionManager, the figures always matched, and the load tests were all successful, so we are definitely using it.

The final code we used goes like this:

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
      }
    });
  }
}


来源:https://stackoverflow.com/questions/11959034/how-to-use-httpasyncclient-with-multithreaded-operation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!