基于线程池和连接池的Http请求
来源:互联网 发布:畅捷通软件 编辑:程序博客网 时间:2024/06/08 06:35
背景:最新项目需求调用http接口,所以打算使用最新的httpClient客户端写一个工具类,写好了以后在实际应用过程中遇到了一些问题,因为数据量还算
大,每次处理大概要处理600-700次请求,平均算下来大概需要20分钟,这个速度虽然是跑在定时任务中的,但是也是不能忍受的,所以有了这个博客.
1.首先想到的解决办法就是多线程发请求了,但是这个有坑,最后会在结果处说明.
2.代码方面如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ExecutorService executor = Executors.newFixedThreadPool(
5
);
FutureTask<Order> future;
for
(TransactionRecord record:list) {
final
String orderNo = record.getOrderNo();
future =
new
FutureTask<Order>(
new
OrderTask(orderNo));
executor.submit(future);
futureList.add(future);
}
class
OrderTask
implements
Callable<Order> {
private
String orderNo;
public
OrderTask(String orderNo) {
this
.orderNo = orderNo;
}
@Override
public
Order call()
throws
Exception {
Order order = orderService.getOrder(orderNo);
//在getOrder中直接调用下面的我封装的http工具类
return
order;
}
}
这是一段很简单的多线程代码,但是其中有一个坑需要大家注意的,不要在上面的循环中直接调用future.get()方法,如果直接调用的话就直接变成阻塞的了,和单线程
就没有区别了,可以自己写一个demo测试一下效率.
3.http方面的代码,可以全部贴出来,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* get
*/
public
static
HttpResultEntry doPost(String url, Map<String, String> params,
String charset)
throws
Exception {
HttpResultEntry resultEntry =
new
HttpResultEntry();
//自定义返回结果
CloseableHttpResponse response =
null
;
//返回结果,释放链接
List<NameValuePair> pairs =
new
ArrayList<>();
;
//参数
if
(StringUtils.isBlank(url)) {
resultEntry.setMsg(
"请求地址异常"
);
resultEntry.setStatus(
404
);
resultEntry.setData(
""
);
return
resultEntry;
}
try
{
if
(params !=
null
&& !params.isEmpty()) {
for
(Map.Entry<String, String> entry : params.entrySet()) {
String value = entry.getValue();
if
(value !=
null
) {
pairs.add(
new
BasicNameValuePair(entry.getKey(), value));
}
}
}
HttpPost httpPost =
new
HttpPost(url);
httpPost.setEntity(
new
UrlEncodedFormEntity(pairs, charset));
response = httpClient.execute(httpPost);
//建立链接得到返回结果
int
statusCode = response.getStatusLine().getStatusCode();
//返回的结果码
if
(statusCode !=
200
) {
httpPost.abort();
resultEntry.setMsg(
"请求异常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(
""
);
LOGGER.info(
"返回异常:{}"
, resultEntry);
return
resultEntry;
}
HttpEntity httpEntity = response.getEntity();
String result =
null
;
if
(httpEntity ==
null
) {
resultEntry.setMsg(
"返回结果异常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(
""
);
return
resultEntry;
}
else
{
result = EntityUtils.toString(httpEntity, charset);
}
resultEntry.setMsg(
"请求正常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(result);
EntityUtils.consume(httpEntity);
//按照官方文档的说法:二者都释放了才可以正常的释放链接
response.close();
return
resultEntry;
}
catch
(Exception e) {
LOGGER.error(
"请求错误:{},错误信息:{}"
, e.getMessage(), e);
throw
new
Exception(
"HTTP请求异常"
);
}
finally
{
if
(response !=
null
) {
try
{
response.close();
}
catch
(IOException e) {
LOGGER.error(
"关闭流异常:{},错误信息:{}"
, e.getMessage(), e);
}
}
}
}
/**
* post
*/
public
static
HttpResultEntry doGet(String url, Map<String, String> params,
String charset)
throws
Exception {
HttpResultEntry resultEntry =
new
HttpResultEntry();
//自定义返回结果
CloseableHttpResponse response =
null
;
//返回结果,释放链接
List<NameValuePair> pairs =
new
ArrayList<>();
//参数
if
(StringUtils.isBlank(url)) {
resultEntry.setMsg(
"请求地址异常"
);
resultEntry.setStatus(
404
);
resultEntry.setData(
""
);
return
resultEntry;
}
try
{
if
(params !=
null
&& !params.isEmpty()) {
for
(Map.Entry<String, String> entry : params.entrySet()) {
String value = entry.getValue();
if
(value !=
null
) {
pairs.add(
new
BasicNameValuePair(entry.getKey(), value));
}
}
url +=
"?"
+ EntityUtils.toString(
new
UrlEncodedFormEntity(pairs, charset));
}
HttpGet httpGet =
new
HttpGet(url);
response = httpClient.execute(httpGet);
//建立链接得到返回结果
int
statusCode = response.getStatusLine().getStatusCode();
if
(statusCode !=
200
) {
httpGet.abort();
resultEntry.setMsg(
"请求异常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(
""
);
LOGGER.info(
"返回异常:{}"
, resultEntry);
return
resultEntry;
}
HttpEntity httpEntity = response.getEntity();
String result =
null
;
if
(httpEntity ==
null
) {
resultEntry.setMsg(
"返回结果异常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(
""
);
return
resultEntry;
}
else
{
result = EntityUtils.toString(httpEntity, charset);
}
resultEntry.setMsg(
"请求正常"
);
resultEntry.setStatus(statusCode);
resultEntry.setData(result);
EntityUtils.consume(httpEntity);
//按照官方文档的说法:二者都释放了才可以正常的释放链接
response.close();
return
resultEntry;
}
catch
(Exception e) {
LOGGER.error(
"请求错误:{},错误信息:{}"
, e.getMessage(), e);
throw
new
Exception(
"HTTP请求异常"
);
}
finally
{
if
(response !=
null
) {
try
{
response.close();
}
catch
(IOException e) {
LOGGER.error(
"关闭流异常:{},错误信息:{}"
, e.getMessage(), e);
}
}
}
}
使用的http连接池,连接池的代码很简单就不粘贴了,首先使用的时候一定要注意最后的释放工作,必须把httpEntry和respose都释放掉,按照官方文档的说法,只有这样才是真的释放了链接的,也就是这个链接才可以被复用.
总结:需要特别注意的是,访问别人的http接口的时候一定不要开太多的线程,免得把别人的接口搞挂了,想我就的到了教训,我在访问一个http的接口的时候开了一百个线程,666次请求跑了3.7秒左右,是很快我也很开心,然后那边数据库受不了压力了,导致报警最后直接开了白名单,尴尬了,所以使用这些的时候一定要考虑这些,开三五个就够了,另外如果开太多线程的话tomcat服务器有可能假死也,不要这么干!
http://www.cnblogs.com/wscit/p/5768447.html
阅读全文
0 0
- 基于线程池和连接池的Http请求
- Http请求连接池
- Http请求连接池
- Http请求连接池
- Http请求连接池
- Http请求连接池 - HttpClient 的 PoolingHttpClientConnectionManager
- 基于线程池的http服务器
- Http请求连接池 - HttpClient 连接池
- web安全 基于http连接的登录请求威胁
- Android 基于线程池的网络请求框架
- HttpAsyncClient (异步http 请求)的连接池使用
- 使用HttpClient的PoolingHttpClientConnectionManager实现Http请求连接池
- HTTP请求的过程&HTTP/1.0和HTTP/1.1的区别&HTTP怎么处理长连接
- HTTP请求的过程&HTTP/1.0和HTTP/1.1的区别&HTTP怎么处理长连接
- 基于HTTP 协议的GET和POST请求服务
- 基于TCP发送http请求建立连接与断开连接的过程
- 线程用来清理 http连接池无效的链接 :
- 基于HTTP协议服务器,线程池
- SOAP协议
- Butterknife bindview @OnClick绑定多控件id
- JAVA中字符串比较equals()和equalsIgnoreCase()的区别
- 长乐集训2017 石子游戏
- Profibus DP-Slave in C
- 基于线程池和连接池的Http请求
- Activity的四种启动模式
- 字符串与数字之间的相互转换、判断大小端(用的是union)
- Linux进程-2.进程间通信概述
- centos编译时报错:lzma.h: No such file or directory
- C++的模板(和java的泛型一样)
- visual studio 2015下OpenGL库的配置教程
- php学习笔记:登录练习
- 天下游安装教程