问题
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