Java 如何在多线程操作中使用HttpAsyncClient?
与这个问题密切相关的是:我想知道apache HttpAsyncClient是否是线程安全的,或者它是否也需要使用多线程HttpConnectionManager或ThreadSafeClientConnManager 如果它确实需要这样的连接管理器,那么异步库中是否存在连接管理器 我能够在异步库中找到PoolgClientAsyncConnectionManager,但我不确定这是否是我所需要的 或者,我考虑使用ThreadLocal为每个线程创建一个HttpAsyncClient对象 请注意,与我前面提到的问题不同,我需要跨会话保持状态独立,即使多个会话访问同一个域。如果在会话1中设置了cookie,则该cookie对会话2不可见。出于这个原因,我还考虑为每个请求创建一个全新的HttpAsyncClient对象,不过我觉得应该有更好的方法 谢谢。您提到“跨会话独立”。如果这仅仅意味着cookies,那么我认为创建您自己的Java 如何在多线程操作中使用HttpAsyncClient?,java,multithreading,apache-httpclient-4.x,Java,Multithreading,Apache Httpclient 4.x,与这个问题密切相关的是:我想知道apache HttpAsyncClient是否是线程安全的,或者它是否也需要使用多线程HttpConnectionManager或ThreadSafeClientConnManager 如果它确实需要这样的连接管理器,那么异步库中是否存在连接管理器 我能够在异步库中找到PoolgClientAsyncConnectionManager,但我不确定这是否是我所需要的 或者,我考虑使用ThreadLocal为每个线程创建一个HttpAsyncClient对象 请注意
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