如何在multithreading操作中使用HttpAsyncClient?

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

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

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

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

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

谢谢。

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

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

Android HttpClient持久性cookie

类似下面的代码会起作用。 我已经重写了ThreadLocal.get()方法,以便在每个请求独立时调用clear() 。 您也可以在execute(...)方法中调用clear。

 private static final ThreadLocal localHttpContext = new ThreadLocal () { @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调用的数量(通过取消(…),完成(…)或失败(…)函数相关的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() { @Override public void cancelled() { // Do stuff } @Override public void completed(HttpResponse httpResponse) { // Do stuff } @Override public void failed(Exception e) { // Do stuff } }); } }