Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在多线程操作中使用HttpAsyncClient?_Java_Multithreading_Apache Httpclient 4.x - Fatal编程技术网

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

Java 如何在多线程操作中使用HttpAsyncClient?,java,multithreading,apache-httpclient-4.x,Java,Multithreading,Apache Httpclient 4.x,与这个问题密切相关的是:我想知道apache HttpAsyncClient是否是线程安全的,或者它是否也需要使用多线程HttpConnectionManager或ThreadSafeClientConnManager 如果它确实需要这样的连接管理器,那么异步库中是否存在连接管理器 我能够在异步库中找到PoolgClientAsyncConnectionManager,但我不确定这是否是我所需要的 或者,我考虑使用ThreadLocal为每个线程创建一个HttpAsyncClient对象 请注意

与这个问题密切相关的是:我想知道apache HttpAsyncClient是否是线程安全的,或者它是否也需要使用多线程HttpConnectionManager或ThreadSafeClientConnManager

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

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

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

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

谢谢。

您提到“跨会话独立”。如果这仅仅意味着cookies,那么我认为创建您自己的
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();
    }
}
private static final threadlocalhttpcontext=
新线程本地(){
@凌驾
受保护的ClientContext初始值(){
返回新的ClientContext();
}
@凌驾
public ClientContext get(){
ClientContext=super.get();
//可以在线程使用之前清除上下文
clientContext.clear();
返回clientContext;
}
};
...
ClientContext ClientContext=localHttpContext.get();
//如果这不在上面的get方法中
//clientContext.clear();
HttpGet HttpGet=新的HttpGet(“http://www.google.com/");
HttpResponse response=clientContext.execute(httpGet);
...
私有静态类ClientContext{
最终HttpClient HttpClient=新的DefaultHttpClient();
最终CookieStore CookieStore=新的基本CookieStore();
final HttpContext localContext=新的BasicHttpContext();
公共ClientContext(){
//将cookie存储绑定到本地上下文
setAttribute(ClientContext.COOKIE_存储,cookieStore);
}
公共HttpResponse执行(HttpUriRequest请求){
//如果您希望每个执行都是独立的
//clientContext.clear();
返回httpClient.execute(请求,httpContext);
}
公共空间清除(){
cookieStore.clear();
}
}

在使用和不使用PoolgClientAsyncConnectionManager进行负载测试后,我们发现,当我们不使用PoolgClientAsyncConnectionManager时,结果不一致

除此之外,我们还跟踪了正在进行的Http调用的数量,以及完成的Http调用的数量(通过相关FutureCallback的取消(…)、完成(…)或失败(…)函数)。在没有PoolgClientAsyncConnectionManager的情况下,在负载较重的情况下,这两个数字有时不匹配,这使我们相信,在某些地方,某些连接正在践踏来自其他线程的连接信息(只是猜测)

无论哪种方式,使用PoolgClientAsyncConnectionManager,数据总是匹配的,负载测试都是成功的,所以我们肯定在使用它

我们使用的最终代码如下所示:

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
      }
    });
  }
}
公共类请求处理器{
私有RequestProcessor实例=新的RequestProcessor();
专用池ClientAsyncConnectionManager pcm=null;
私有HttpAsyncClient HttpAsyncClient=null;
私有请求处理器(){
//初始化PoolgClientAsyncConnectionManager和HttpAsyncClient
}
公共无效流程(…){
此.httpAsyncClient.execute(httpMethod,
new BasicHttpContext(),//为每个请求使用单独的HttpContext,以便在请求之间不共享信息
新未来回调(){
@凌驾
公众假期取消(){
//做事
}
@凌驾
公共无效已完成(HttpResponse HttpResponse){
//做事
}
@凌驾
公共作废失败(异常e){
//做事
}
});
}
}

谢谢。这看起来和我已经得到的非常接近,除了清理饼干。然而,饼干只是一个例子。我的意思是,我需要每个会话完全独立于其他会话。从一个会话到另一个会话,根本看不到任何数据。饼干是我唯一需要担心的吗?我想是的@Tinclon。这里有一些文档在提到HttpClient state时似乎只谈论cookies:身份验证信息是@Tinclon需要担心的另一件事,但只有在会话中自己设置身份验证用户名/密码时才需要这样做。在这种情况下,这无疑解决了会话信息的独立性问题,但在尝试使用同一客户机处理多个会话时,它仍然无助于消除线程之间的干扰。(参见我对原始问题的评论)。为什么要使用相同的客户端@Tinclon?另外,在查看ApacheHttpClient代码时,我没有看到
execute(…)
是同步的。连接管理器是可选的,对吗?我认为ThreadLocal不起作用。使用HttpClient,th