与此问题密切相关:How to use HttpClient with multithreaded operation?,我想知道apache HttpAsyncClient是否是线程安全的,或者它是否也需要使用MultiThreadedHttpConnectionManager或ThreadSafeClientConnManager。
如果确实需要这样的连接管理器,那么异步库中是否存在一个连接管理器?
我能够在异步库中找到PoolingClientAsyncConnectionManager,但我不确定这是否是我需要的。
或者,我正在考虑使用ThreadLocal为每个线程创建一个HttpAsyncClient对象。
请注意,与我前面提到的问题不同,即使多个会话访问同一个域,我也需要状态在会话中独立。如果在会话1中设置了cookie,则cookie应不对会话2可见。出于这个原因,我还考虑为每个请求创建一个全新的HttpAsyncClient对象,尽管我得到了印象应该是更好的方式。
感谢。
答案 0 :(得分:1)
你提到“跨会议独立”。如果这仅仅意味着cookie,那么我认为创建自己的CookieStore
,当你的每个线程使用HttpClient
时,它就会被清除。
我会使用ThreadLocal
来创建每个线程的客户端,不要使用共享连接管理器,然后积极地清除cookie。这个答案对于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();
}
}
答案 1 :(得分:1)
使用和不使用PoolingClientAsyncConnectionManager进行负载测试后,我们发现当我们不使用PoolingClientAsyncConnectionManager时,我们得到了不一致的结果。
除此之外,我们还跟踪了我们正在进行的Http调用的数量,以及已完成的Http调用的数量(通过取消(...),完成(...)或失败(...) 。)相关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
}
});
}
}