基于线程池和连接池的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) {
           finalString orderNo = record.getOrderNo();
           future =new FutureTask<Order>(newOrderTask(orderNo));
           executor.submit(future);
           futureList.add(future);
       }
 
   classOrderTask implementsCallable<Order> {
       privateString orderNo;
       publicOrderTask(String orderNo) {
           this.orderNo = orderNo;
       }
       @Override
       publicOrder call() throwsException {
           Order order = orderService.getOrder(orderNo);//在getOrder中直接调用下面的我封装的http工具类
           returnorder;
       }
   }

 这是一段很简单的多线程代码,但是其中有一个坑需要大家注意的,不要在上面的循环中直接调用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
  */
 publicstatic 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("");
         returnresultEntry;
     }
     try{
         if(params != null&& !params.isEmpty()) {
             for(Map.Entry<String, String> entry : params.entrySet()) {
                 String value = entry.getValue();
                 if(value != null) {
                     pairs.add(newBasicNameValuePair(entry.getKey(), value));
                 }
             }
         }
         HttpPost httpPost =new HttpPost(url);
         httpPost.setEntity(newUrlEncodedFormEntity(pairs, charset));
         response = httpClient.execute(httpPost);    //建立链接得到返回结果
         intstatusCode = response.getStatusLine().getStatusCode();     //返回的结果码
         if(statusCode != 200) {
             httpPost.abort();
             resultEntry.setMsg("请求异常");
             resultEntry.setStatus(statusCode);
             resultEntry.setData("");
             LOGGER.info("返回异常:{}", resultEntry);
             returnresultEntry;
         }
         HttpEntity httpEntity = response.getEntity();
         String result =null;
         if(httpEntity == null) {
             resultEntry.setMsg("返回结果异常");
             resultEntry.setStatus(statusCode);
             resultEntry.setData("");
             returnresultEntry;
         }else {
             result = EntityUtils.toString(httpEntity, charset);
         }
         resultEntry.setMsg("请求正常");
         resultEntry.setStatus(statusCode);
         resultEntry.setData(result);
 
         EntityUtils.consume(httpEntity);       //按照官方文档的说法:二者都释放了才可以正常的释放链接
         response.close();
         returnresultEntry;
     }catch (Exception e) {
         LOGGER.error("请求错误:{},错误信息:{}", e.getMessage(), e);
         thrownew Exception("HTTP请求异常");
     }finally {
         if(response != null) {
             try{
                 response.close();
             }catch (IOException e) {
                 LOGGER.error("关闭流异常:{},错误信息:{}", e.getMessage(), e);
             }
         }
     }
 }
 
 /**
  * post
  */
 publicstatic 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("");
         returnresultEntry;
     }
     try{
         if(params != null&& !params.isEmpty()) {
             for(Map.Entry<String, String> entry : params.entrySet()) {
                 String value = entry.getValue();
                 if(value != null) {
                     pairs.add(newBasicNameValuePair(entry.getKey(), value));
                 }
             }
             url +="?" + EntityUtils.toString(newUrlEncodedFormEntity(pairs, charset));
         }
         HttpGet httpGet =new HttpGet(url);
         response = httpClient.execute(httpGet);    //建立链接得到返回结果
         intstatusCode = response.getStatusLine().getStatusCode();
         if(statusCode != 200) {
             httpGet.abort();
             resultEntry.setMsg("请求异常");
             resultEntry.setStatus(statusCode);
             resultEntry.setData("");
             LOGGER.info("返回异常:{}", resultEntry);
             returnresultEntry;
         }
         HttpEntity httpEntity = response.getEntity();
         String result =null;
         if(httpEntity == null) {
             resultEntry.setMsg("返回结果异常");
             resultEntry.setStatus(statusCode);
             resultEntry.setData("");
             returnresultEntry;
         }else {
             result = EntityUtils.toString(httpEntity, charset);
         }
         resultEntry.setMsg("请求正常");
         resultEntry.setStatus(statusCode);
         resultEntry.setData(result);
 
         EntityUtils.consume(httpEntity);       //按照官方文档的说法:二者都释放了才可以正常的释放链接
         response.close();
         returnresultEntry;
     }catch (Exception e) {
         LOGGER.error("请求错误:{},错误信息:{}", e.getMessage(), e);
         thrownew 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

原创粉丝点击