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

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

时间: 2024-12-15 09:35:33

Httpclient通过FutureRequestExecutionService异步访问的相关文章

使用ab.exe监测100个并发/100次请求情况下同步/异步访问数据库的性能差异

ab.exe介绍 ab.exe是apache server的一个组件,用于监测并发请求,并显示监测数据 具体使用及下载地址请参考:http://www.cnblogs.com/gossip/p/4398784.html 本文的目的 通过webapi接口模拟100个并发请求下,同步和异步访问数据库的性能差异 创建数据库及数据 --创建表结构 CREATE TABLE dbo.[Cars] ( Id INT IDENTITY(1000,1) NOT NULL, Model NVARCHAR(50) 

ASP.NET MVC中使用ASP.NET AJAX异步访问WebService

使用过ASP.NET AJAX的朋友都知道,怎么通过ASP.NET AJAX在客户端访问WebService,其实在ASP.NET MVC中使用ASP.NET AJAX异步访问WebService 也没什么大的差别. 在ASP.NET应用程序里使用ASP.NET AJAX访问WebService通常都是通过ScriptMananger引入WebService生成客户端代理的方法,同时也可以使用Microsoft Ajax Library来完成.本文将介绍在ASP.NET MVC中使用ASP.NE

jQuery的AJax异步访问

用一个例子用以说明:点击按钮,将input内用户输入的数据发送给服务端,并将结果返回给页面. 首先是html承载内容: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>AJax异步访问</title> <script src="js/jquery-2.1.3.min.js">

android httpClient 支持HTTPS的访问方式

项目中Android https请求地址遇到了这个异常(无终端认证): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 是SSL协议中没有终端认证. 没有遇到过的问题,于是无奈的去找度娘....... 看了不少大神的博客后得到的解决方案如下:     /**      * Post请求连接Https服务      * @param serverURL  请求地址      * @param jsonStr    请求报文

TNetHttpClient支持异步访问(Delphi 10.1 Berlin,红鱼儿的博客)

Delphi 10.1进一步改进自Delphi 10带来的Http访问控件TNetHttpClient,支持异步访问,同时增加ConnectionTimeout及ResponseTimeout两个超时属性.你也许会问,这有什么?其他的语言早就有了,而我想到的确实别看这些常规的功能增加,他可以跨平台的啊,熟知Delphi跨平台的开发者一说就明白,这是跨win,osx,android,ios的,今年底还要linux.我又说多了,好象劝你也来用delphi似的.我们看一下如何使用异步处理Http请求.

Android与WebView的同步和异步访问机制

大家都知道,通过WebView,我们可以在Android客户端,用Web开发的方式来开发我们的应用. 如果一个应用就是单纯一个WebView,所有的逻辑都只需要在网页上交互的话,那我们其实就只需要通过html和javascript来跟服务器交互就可以了. 但是很多情况下,我们的应用不是单纯一个WebView就可以了,有可能会需要运用到Android本身的应用,比如拍照,就需要调用Android本身的照像机等,要产生震动,在需要运用到手机特性的一些场景下,肯定需要这么一套机制在javascript

Vert.x 异步访问数据库 MySQL

Vert.x提供异步访问数据库的API,数据库操作是一个耗时操作,使用传统的同步模型,容易阻塞线程,导致整体性能下降,因此我们对于数据库操作,需要使用Vert.x提供的异步API. Vert.x提供的API层级非常低,可以说是仅仅在原生JDBC基础上封装了一层异步接口.所有的对数据库操作都需要通过编写SQL来完成,参数的封装和结果的获取都需要手动的来实现,对于习惯使用ORM框架的开发者可能会非常的不习惯. 先来通过一个查询数据库的案例来演示如何使用Vert.x提供的异步API 基本操作1.引入数

一个异步访问redis的内存问题

| 分类 redis? | 遇到一个redis实例突然内存飙高的案例, 具体症状如下: 客户端使用异步访问模式 单个请求的回包很大,hgetall一个8M的key 由于访问量比较大,已经登录不上redis了, 看不到具体在做什么做操, 因此使用perf来看下调用栈, 此处且按下不表. 为何内存会飙高呢,我们线下重现一下: import redis import time r=redis.Redis("127.0.0.1", 9988) pipe = r.pipeline() key=&

(办公)访问其他系统接口httpClient,异步访问

访问其他系统接口httpClient,但是都是同步的,同步意味当前线程是阻塞的,只有本次请求完成后才能进行下一次请求;异步意味着所有的请求可以同时塞入缓冲区,不阻塞当前的线程; httpClient请求,访问其他系统可能无响应,锁死,访问请求上线种种问题,这些问题就像苍蝇嗡嗡嗡的在你耳边,那么解决他可以设置超时时间,但是访问一个接口将近1分钟,这个是不应该的,所以还是要异步请求其他系统的接口,我们可以使用多线程来做,建立一个线程池,只指定10个线程,然后调用方法.(好主意) 下面是举个sprin