170314、工具:apache httpClient多线程并发情况下安全实用及工具类分享
简单用法介绍:介绍来源网络
建立连接:在HttpClient中使用多线程的一个主要原因是可以一次执行多个方法。在执行期间,每一个方法都使用一个HttpConnection实例。由于在同一时间多个连接只能安全地用于单一线程和方法和有限的资源,我们就必须确保连接分配给正确的方法。而MultiThreadedHttpConnectionManager完全可以代替我们完成这一项工作,这样我们就不必去考虑多线程带来安全的问题。
MultiThreadedHttpConnectionManager connectionManager =new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
以上代码中的HttpClient就在多线程中执行多个方法了。当我们再次调用httpClient.executeMethod()方法时,就会去Connection Manager中去请求HttpConneciton的实例,这样就避免了线程安全问题,因为HttpClient已经帮我们做了。
释放连接:Connection Management比较重要的是当连接不再使用时,一定要手动释放。这样做的原因是HttpClient不能够确定哪个方法不被使用,哪个方法还在使用。这是因为Response body不是由HttpClient来自动读取其数据的,而是由使用HttpClient的应用程序来完成的。当读取Response的数据是时,必须使用此方法的连接。这样,在Response的数据在读取前,HttpClient是没有释放连接的。所有这就要求在读取完Response的数据后,应用程序及时的使用releaseConnection()方法来释放连接。特别注意,无论执行的方法或是否也不例外被抛出。对于每一个HttpClient.executeMethod方法必须有一个method.releaseConnection ( )来释放连接。
重用HttpClient实例:一般说来,建议一个通讯组件,甚至说一个应用软件就始终维持一个HttpClient对象实例存在。但是如果你的应用很稀罕才用到它,而且还不允许这么一个实例一直存在,那么,这里强烈建议,一定要显式地shut down 它的MultiThreadedHttpConnectionManager 。这样做是确保连接池里的Connection得到释放。
HttpMethod并发执行:如果应用程序逻辑允许并发执行多个HTTP请求,(例如对多个服务器的多个并发请求,或对同一个服务器代表不同用户身份的多个请求) ,应用程序可以为每一个HTTP session开启一个专门的线程,这样的设计自然将带来显著的性能提升。 而当使用一个线程安全的连接管理器MultiThreadedHttpConnectionManager 时,HttpClient能保证线程安全。这样,多个线程可以共享这么一个线程安全的HttpClient实例。请注意,应用程序的每个各自执行的线程必须使用各自的HttpMethod实例;并且可配置各自的HttpState实例和/或HostConfiguration实例(代表一个特定的会话状态和主机配置)。这个共享的HttpClient和其标配的MultiThreadedHttpConnectionManager将为各线程带来最高的性能。
使用流来发送和接收数据:HttpClient同时支持Stream和String/byte[]两种方式来发送和接受数据,但是由于String/byte[]的方式会造成内存中有一份数据的拷贝或缓存,那么当请求或应答报文比较大,或者在高并发的应用中,使用String/byte[]就会造成额外的内存开销,所以使用流的方式来传输数据是更好的选择。
HttpClient的三种超时说明
/* 从连接池中取连接的超时时间 */
ConnManagerParams.setTimeout(params, 1000);
/* 连接超时 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 请求超时 */
HttpConnectionParams.setSoTimeout(params, 4000);
第一行设置ConnectionPoolTimeout:这定义了从ConnectionManager管理的连接池中取出连接的超时时间,此处设置为1秒。
第二行设置ConnectionTimeout: 这定义了通过网络与服务器建立连接的超时时间。Httpclient包中通过一个异步线程去创建与服务器的socket连接,这就是该socket连接的超时时间,此处设置为2秒。
第三行设置SocketTimeout: 这定义了Socket读数据的超时时间,即从服务器获取响应数据需要等待的时间,此处设置为4秒。
以上3种超时分别会抛出ConnectionPoolTimeoutException,ConnectionTimeoutException与SocketTimeoutException。
工具类:jar包commons-httpclient-3.1.jar
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class HttpClientTemplate {
private static Logger logger = LoggerFactory.getLogger(HttpClientTemplate.class);
private MultiThreadedHttpConnectionManager multiThreadConnManager;
private HttpClient client;
public HttpClientTemplate() {
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler());
params.setMaxTotalConnections(10);
params.setDefaultMaxConnectionsPerHost(5);
params.setSoTimeout(10 * 1000);
params.setConnectionTimeout(10 * 1000);
multiThreadConnManager = new MultiThreadedHttpConnectionManager();
multiThreadConnManager.setParams(params);
}
private HttpClient getHttpClient() {
if (client == null)
synchronized (this) {
client = new HttpClient(multiThreadConnManager);
HttpClientParams params = new HttpClientParams();
params.setContentCharset("UTF-8");
client.setParams(params);
}
return client;
}
//生成get方法
private GetMethod genMethod(String baseUrl, String queryString) {
GetMethod get = new GetMethod(baseUrl);
get.setQueryString(queryString);
return get;
}
//生成get方法
private GetMethod genMethod(String baseUrl, Map<String, Object> paramMap) {
GetMethod get = new GetMethod(baseUrl);
HttpMethodParams params = new HttpMethodParams();
params.setContentCharset("UTF-8");
get.setParams(params);
if (paramMap != null) {
NameValuePair[] nvp = new NameValuePair[paramMap.values().size()];
int i = 0;
for (Map.Entry<String, Object> entry: paramMap.entrySet()) {
nvp[i++] = new NameValuePair(entry.getKey(), entry.getValue()
.toString());
}
get.setQueryString(nvp);
}
return get;
}
public String execute(String baseUrl, Map<String, Object> paramMap) {
if(logger.isDebugEnabled()) {
logger.debug("[sending] url={}, param={}", baseUrl, JSON.toJSONString(paramMap));
}
try {
GetMethod method = genMethod(baseUrl, paramMap);
String result = execute(method);
if(logger.isDebugEnabled()) {
logger.debug("[receiving] result ={}, url={}, param={}",result, baseUrl, JSON.toJSONString(paramMap));
}
return result;
}
catch(Exception e) {
logger.error("[http exception] url={}, param={}", baseUrl, JSON.toJSONString(paramMap), e);
return null;
}
}
//json格式请求
public String excuteJson(String baseUrl, Map<String, Object> paramMap)
throws HttpException, IOException
{
if(logger.isDebugEnabled()) {
logger.debug("[sending json] url={}, param={}", baseUrl, JSON.toJSONString(paramMap));
}
JSONObject json = new JSONObject();
json.putAll(paramMap);
PostMethod method = new PostMethod(baseUrl);
RequestEntity requestEntity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
method.setRequestEntity(requestEntity);
String result = execute(method);
if(logger.isDebugEnabled()) {
logger.debug("[receiving json] result ={}, url={}, param={}",result, baseUrl, JSON.toJSONString(paramMap));
}
return result;
}
//post请求
public String executePost(String baseUrl, Map<String, Object> paramMap){
try {
if(logger.isDebugEnabled()) {
logger.debug("[sending post] url={}, param={}", baseUrl, JSON.toJSONString(paramMap));
}
PostMethod method = new PostMethod(baseUrl);
HttpMethodParams params = new HttpMethodParams();
params.setContentCharset("UTF-8");
method.setParams(params);
if (paramMap != null) {
NameValuePair[] nvp = new NameValuePair[paramMap.values().size()];
int i = 0;
for (Map.Entry<String, Object> entry: paramMap.entrySet()) {
nvp[i++] = new NameValuePair(entry.getKey(), entry.getValue()
.toString());
}
method.addParameters(nvp);
}
String result = execute(method);
if(logger.isDebugEnabled()) {
logger.debug("[receiving post] result ={}, url={}, param={}",result, baseUrl, JSON.toJSONString(paramMap));
}
return result;
}
catch(Exception e) {
logger.error("[http post exception] url={}, param={}", baseUrl, JSON.toJSONString(paramMap), e);
return null;
}
}
public String executePost(String baseUrl, Map<String, Object> paramMap,
Map<String, Object> headerParams) throws HttpException, IOException {
if(logger.isDebugEnabled()) {
logger.debug("[sending head] url={}, param={}, head={}", baseUrl,
JSON.toJSONString(paramMap), JSON.toJSONString(headerParams));
}
PostMethod method = new PostMethod(baseUrl);
HttpMethodParams params = new HttpMethodParams();
params.setContentCharset("UTF-8");
method.setParams(params);
if (paramMap != null) {
NameValuePair[] nvp = new NameValuePair[paramMap.values().size()];
int i = 0;
for (Map.Entry<String, Object> entry: paramMap.entrySet()) {
nvp[i++] = new NameValuePair(entry.getKey(), entry.getValue()
.toString());
}
method.addParameters(nvp);
}
if (headerParams != null) {
// HttpMethodParams mparams = new HttpMethodParams();
// mparams.setContentCharset("UTF-8");
// mparams.setVirtualHost(headerParams.get("hostUrl").toString());
// method.setParams(mparams);
method.getParams().setVirtualHost(
headerParams.get("hostUrl").toString());
}
String result = execute(method, headerParams);
if(logger.isDebugEnabled()) {
logger.debug("[receiving head] result ={}, url={}, param={}, head={}",result, baseUrl,
JSON.toJSONString(paramMap), JSON.toJSONString(headerParams));
}
return result;
}
public String execute(String url) throws HttpException, IOException {
GetMethod method = new GetMethod(url);
return execute(method);
}
public String execute(String baseUrl, String queryString)
throws HttpException, IOException {
GetMethod method = genMethod(baseUrl, queryString);
return execute(method);
}
private String execute(HttpMethod method) throws HttpException, IOException {
try {
int statusCode = getHttpClient().executeMethod(method);
if (200 != statusCode) {
throw new HttpException("status code: " + statusCode);
} else {
// return method.getResponseBodyAsString();
InputStream resStream = method.getResponseBodyAsStream();
BufferedReader br = new BufferedReader(new InputStreamReader(
resStream, "UTF-8"));
StringBuffer resBuffer = new StringBuffer();
String resTemp = "";
while ((resTemp = br.readLine()) != null) {
resBuffer.append(resTemp);
}
return resBuffer.toString();
}
} finally {
if (null != method)
method.releaseConnection();
}
}
private String execute(HttpMethod method, Map<String, Object> headerParams)
throws HttpException, IOException {
try {
HttpClient httpClient = getHttpClient();
if (headerParams != null) {
HostConfiguration hf = new HostConfiguration();
if (headerParams.get("hostUrl") != null) {
hf.setHost(headerParams.get("hostUrl").toString(), 80,
Protocol.getProtocol("http"));
}
httpClient.setHostConfiguration(hf);
}
int statusCode = httpClient.executeMethod(method);
if (200 != statusCode) {
throw new HttpException("status code: " + statusCode);
} else {
// return method.getResponseBodyAsString();
InputStream resStream = method.getResponseBodyAsStream();
BufferedReader br = new BufferedReader(new InputStreamReader(
resStream, "UTF-8"));
StringBuffer resBuffer = new StringBuffer();
String resTemp = "";
while ((resTemp = br.readLine()) != null) {
resBuffer.append(resTemp);
}
return resBuffer.toString();
}
} finally {
if (null != method)
method.releaseConnection();
}
}
public static class Factory {
private static HttpClientTemplate instance = new HttpClientTemplate();
public static HttpClientTemplate getClient() {
return Factory.instance;
}
}
public static void main(String[] args) {
HttpClientTemplate clientTemplate = HttpClientTemplate.Factory.instance;
Map<String, Object> paramMap = new LinkedHashMap<>();
String result = clientTemplate.executePost("", paramMap);
}
}
170314、工具:apache httpClient多线程并发情况下安全实用及工具类分享的更多相关文章
- 喜提JDK的BUG一枚!多线程的情况下请谨慎使用这个类的stream遍历。
你好呀,我是歪歪. 前段时间在 RocketMQ 的 ISSUE 里面冲浪的时候,看到一个 pr,虽说是在 RocketMQ 的地盘上发现的,但是这个玩意吧,其实和 RocketMQ 没有任何关系. ...
- 多线程并发情况下 重复insert问题
代码逻辑: if(数据不存在){ insert(); } 线程启动后,发现数据库表中有相同的记录 解决方案 synchronized同步代码块即加同步锁,synchronized同步代码块的功能: 当 ...
- PHP通过加锁实现并发情况下抢码实现
需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: 实现: 1.在不考虑并发的情况下实现: function get_code($len){ ...
- PHP通过加锁实现并发情况下抢码功能
本文基于php语言使用加锁实现并发情况下抢码功能,特定时间段开放抢码并不允许开放的码重复: 需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: ...
- Jackson高并发情况下,产生阻塞
情况:在高并发情况下,查看线程栈信息,有大量的线程BLOCKED. 从线程栈得知,线程栈中出现了阻塞,锁在了com.fasterxml.jackson.databind.ser.SerializerC ...
- Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载
Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...
- c# redis 利用锁(StackExchange.Redis LockTake)来保证数据在高并发情况下的正确性
之前有写过一篇介绍c#操作redis的文章 http://www.cnblogs.com/axel10/p/8459434.html ,这篇文章中的案例使用了StringIncrement来实现了高并 ...
- 面试官问:HashMap在并发情况下为什么造成死循环?一脸懵
这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的. 那么面试官就会紧接 ...
- 关于WCF服务在高并发情况下报目标积极拒绝的异常处理
最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是 ...
随机推荐
- 严重: Dispatcher initialization failed java.lang.RuntimeException: java.lang.reflect.Invoc
错误提示:严重: Dispatcher initialization failed java.lang.RuntimeException: java.lang.reflect.InvocationTa ...
- centOS7 配置DNS上外网
CentOS7 linux下DNS的永久性添加 I.网上很多讲的dns的永久性添加其实都是暂时性添加,重启网卡后就会丢失.代码如下: echo nameserver 8.8.8.8 > /etc ...
- 解决The markup in the document following the root element must be well-formed.
出现问题的代码: <security-constraint> <web-resource-collection> <web-resource-name>Regist ...
- python文件目录操作大全
python只获取当前目录下的文件夹及文件名 list = os.listdir(rootdir)#列出目录下的所有文件和目录 for line in list: filepath = os.path ...
- Android中<uses-sdk>属性和target属性分析
1. 概要 <uses-sdk> 用来描述该应用程序可以运行的最小和最大API级别,以及应用程序开发者设计期望运行的平台版本.通过在manifest清单文件中添加该属性,我们可以更好的控制 ...
- PHP uxf framework 在模版中加入url标签
1. 确保不修改discuz代码: 2. 继承discuz template类,重载parse_template 方法:由于discuz在模版引擎这一块没有考虑扩展性,对标签的解析全部写在一个方法中, ...
- Mybatis Batch 批量操作
Mybatis Batch 批量操作 http://www.blogjava.net/diggbag/articles/mybatis.html
- Android——Activity和Intent及Activity的生命周期
实验Activity的生命周期 package com.example.chenshuai.test; import android.app.Activity; import android.os.B ...
- vector--C++ STL 学习
vector对应的数据结构为数组,而且是动态数组,也就是说我们不必关心该数组事先定义的容量是多少,它的大小会动态增长.与数组类似的是,我们可以在末尾进行元素的添加和删除,也可以进行元素值的随机访问和修 ...
- 记一次线上Kafka消息堆积踩坑总结
2018年05月31日 13:26:59 xiaoguozi0218 阅读数:2018更多 个人分类: 大数据 年后上线的系统,与其他业务系统的通信方式采用了第三代消息系统中间件Kafka.由于是 ...