Httpclient的异步访问,是一个比较强大的功能,能够针对比较复杂、有一定并发量的情况下的使用。
能够控制访问的超时、取消等操作。并根据回调,异步获取线程执行的结果,但是在使用异步访问的时候要注意,不要阻塞线程。
package test.ffm83.commons.httpClient;
import java.io.IOException;
importjava.util.concurrent.CancellationException;
importjava.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
importorg.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
importorg.apache.http.client.ResponseHandler;
importorg.apache.http.client.methods.HttpGet;
importorg.apache.http.client.protocol.HttpClientContext;
importorg.apache.http.concurrent.FutureCallback;
importorg.apache.http.impl.client.FutureRequestExecutionService;
import org.apache.http.impl.client.HttpClientBuilder;
importorg.apache.http.impl.client.HttpRequestFutureTask;
/**
*httpClient 的异步访问处理;基于4.x版本的FutureRequestExecutionService
*
*@author 范芳铭
*/
public class EasyAsyncRequestFuture {
publicstatic void main(String[] args) throws Exception {
HttpClienthttpclient = HttpClientBuilder.create()
.setMaxConnPerRoute(5).setMaxConnTotal(5).build();
ExecutorServiceexecService = Executors.newFixedThreadPool(5);
FutureRequestExecutionServicerequestExecService = new FutureRequestExecutionService(
httpclient,execService);
Stringurl = "http://blog.csdn.net/ffm83/article/details/41944921";
try{
//因为是一个asynchronous, 我们必须提供一个ResponseHandler
ResponseHandler<Boolean>handler = new ResponseHandler<Boolean>() {
publicBoolean handleResponse(HttpResponse response)
throwsClientProtocolException, IOException {
//如果能访问就认为OK
returnresponse.getStatusLine().getStatusCode() == 200;
}
};
//创建一个简单的请求
HttpGetrequest1 = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTask1 = requestExecService
.execute(request1,HttpClientContext.create(), handler);
BooleanwasItOk1 = futureTask1.get();
System.out.println(StringUtils.leftPad("1创建请求 ok? " + wasItOk1,
60,"-"));
// 取消一个已经发出的请求
try{
HttpGetrequest2 = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTask2 = requestExecService
.execute(request2,HttpClientContext.create(), handler);
futureTask2.cancel(true);
BooleanwasItOk2 = futureTask2.get();
System.out.println(StringUtils.leftPad("2取消请求, 不应该被执行: "
+wasItOk2 + wasItOk1, 60, "-"));
}catch (CancellationException e) {
System.out.println(StringUtils.rightPad("2取消请求, 应该被执行", 60,
"-"));
}
//设置请求超时
try{
HttpGetrequest3 = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTask3 = requestExecService
.execute(request3,HttpClientContext.create(), handler);
//如果响应非常快的应用,想要测试这个结果,需要调整超时的时间
BooleanwasItOk3 = futureTask3.get(1, TimeUnit.MILLISECONDS);
System.out.println(StringUtils.leftPad(
"3超时请求 ok? " + wasItOk3, 60, "-"));
}catch (TimeoutException e) {
System.out.println(StringUtils.rightPad("3超时", 60, "-"));
}
FutureCallback<Boolean>callback = new FutureCallback<Boolean>() {
publicvoid completed(Boolean result) {
System.out.println("completedwith " + result);
}
publicvoid failed(Exception ex) {
System.out.println("failedwith " + ex.getMessage());
}
publicvoid cancelled() {
System.out.println("cancelled");
}
};
//创建一组简单的有回调的请求
try{
HttpGetreqCallbackA = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTaskA = requestExecService
.execute(reqCallbackA,HttpClientContext.create(),
handler,callback);
BooleanisCallbackAok = futureTaskA.get(10, TimeUnit.SECONDS);
System.out.println(StringUtils.leftPad("4A回调ok? "
+isCallbackAok, 60, "-"));
}catch (TimeoutException e) {
System.out.println("4A超时");
}
//取消
try{
System.out.println(StringUtils.center("4取消", 60, "-"));
HttpGetreqCallbackB = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTaskB = requestExecService
.execute(reqCallbackB,HttpClientContext.create(),
handler,callback);
futureTaskB.cancel(true);
BooleanisCallbackBok = futureTaskB.get(1, TimeUnit.SECONDS);
System.out.println(StringUtils.leftPad("4B回调ok? "
+isCallbackBok, 60, "-"));
}catch (TimeoutException e) {
System.out.println("4B超时");
}catch (CancellationException e) {
System.out.println("4B取消");
}
//超时
try{
System.out.println(StringUtils.center("4超时", 60, "-"));
HttpGetreqCallbackC = new HttpGet(url);
HttpRequestFutureTask<Boolean>futureTaskC = requestExecService
.execute(reqCallbackC,HttpClientContext.create(),
handler,callback);
BooleanisCallbackCok = futureTaskC.get(1,
TimeUnit.MILLISECONDS);
System.out.println(StringUtils.leftPad("4C回调ok? "
+isCallbackCok, 60, "-"));
}catch (TimeoutException e) {
System.out.println("4C超时");
}catch (CancellationException e) {
System.out.println("4C取消");
}
//异常
try{
System.out.println(StringUtils.center("4异常", 60, "-"));
HttpGetreqCallbackD = new HttpGet("http://www.不可能网站.ccom");
HttpRequestFutureTask<Boolean>futureTaskD = requestExecService
.execute(reqCallbackD,HttpClientContext.create(),
handler,callback);
BooleanisCallbackDok = futureTaskD.get(1,
TimeUnit.SECONDS);
System.out.println(StringUtils.leftPad("4D回调ok? "
+isCallbackDok, 60, "-"));
}catch (TimeoutException e) {
System.out.println("4D超时");
}catch (CancellationException e) {
System.out.println("4D取消");
}
}finally {
requestExecService.close();
}
}
}
运行结果如下:
---------------------------------------------1创建请求 ok? true
2 取消请求, 应该被执行-----------------------------------------------
3 超时--------------------------------------------------------
completed with true
------------------------------------------------4A回调ok? true
----------------------------4 取消----------------------------
cancelled
4B取消
----------------------------4 超时----------------------------
4C超时
----------------------------4 异常----------------------------
4D超时
failed with socket closed
failed with Connect to www.不可能网站.ccom:80 [www.不可能网站.ccom/180.168.41.175]failed: Connection timed out: connect
线程的效率是一个复杂的概念,有的追求连接数的多,有的追求吞吐量的大,有的追求可访问资源的成功率,使用异步的方法,在一些场景并不一定能够超过普通的线程使用的效率,网上有一个很有意思的举例,记录下来:
异步请求关注的是非阻塞模式下可以利用线程完成更多的事情,对于某件事情本身来说,往往意味着降低效率。
信息系统设计原理源于现实生活。
我举个例子来说,某小餐馆,中午忙的时候经常会同时来5桌客人(任务),它有三种上菜策略:
1、请1个大厨,按顺序来,只有完整搞定1桌客人后,大厨才空闲出来可以服务下一桌客人;
2、请5个大厨,每个大厨及其小工负责1桌客人,同样完整搞定1桌客人后,大厨才可以服务下一桌客人;
3、请1个大厨,轮着来,让几个小工(外设等)负责分别备菜,哪个备好了炒哪个;
根据单桌客人服务速度来说:
1、晚轮到被服务的客户恐怕就要拍桌子走人了(超时了);
2、客人最喜欢了,但是这小店怕是要倒闭;
3、单个客人服务时间变长,总服务时间也变长(上下文切换时等待大厨),但客人能接受、馆子也能活下去。
所以如果你想问真的对XXOO有提升么?那么取决于你关注的是啥。
这个例子真好,鼓掌。 :)