首页 > 代码库 > Httpclient通过FutureRequestExecutionService异步访问

Httpclient通过FutureRequestExecutionService异步访问

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有提升么?那么取决于你关注的是啥。

 

这个例子真好,鼓掌。 :)

 

Httpclient通过FutureRequestExecutionService异步访问