java httpclient 关闭_【Java系列007】HttpClient调用:你考虑过关闭连接、并发了吗?...

你好!我是miniluo,今天和你分享使用HttpClient过程中,未考虑释放连接和并发导致的坑。

HttpClient在项目中还是比较常见的,主要都是通过GET或POST请求第三方以获取响应结果。前段时间还了解到也有企业用它来做爬虫。下面我们就从两方面来一起学习HttpClient。

强占着不放

我们先来看一张因未释放连接导致的异常图。

d9907b38aa3952d91310d3c1734652af.png

我们再来看代码,代码很简单,用一个static修饰HttpClient的一个对象,也是用static的方式实例化(并发下,static实例化的对象是线程不安全的)。

1@Slf4j

2public class MyHttpClientTest{

3    private static HttpClient client;

4    static {

5        RequestConfig requestConfig = RequestConfig.custom()

6                .setConnectTimeout(5000)

7                .setConnectionRequestTimeout(3000)

8                .setSocketTimeout(5000).build();

9        client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)

10                .build();

11    }

12

13    @Test

14    public void testHttpClient(){

15        for (int i = 0; i 

16            String url = "http://127.0.0.1:9092/learn/product/get/12";

17            HttpGet httpGet = new HttpGet(url);

18            try {

19                HttpResponse res = client.execute(httpGet);

20            } catch (IOException e) {

21                log.error("异常: ",e);

22                return;

23            }

24        }

25    }

26}

我们看回异常图,图中有2个红框,我们先来看第一个红框的“[total kept alive: 0; route allocated: 2 of2; total allocated: 2 of 20]”,这个DEBUG级别日志描述的什么意思呢?也就是说这个route下共有2个连接,已用2个;pool共有20个,已用2个。再来看第二个红框“Timeout waiting for connection from pool”,从连接池获取连接等待超时。奇怪吧,这顺序执行也会出现?这其实是前两个连接响应结果回来后,并没有释放连接资源,导致后面的请求等待超时。

我们看看PoolingHttpClientConnectionManager类的构造函数,其给Pool初始化时给maxConnPerRoute和maxConnTotal设置了默认值。

1    public PoolingHttpClientConnectionManager(

2        final HttpClientConnectionOperator httpClientConnectionOperator,

3        final HttpConnectionFactory connFactory,

4        final long timeToLive, final TimeUnit tunit){

5        super();

6        this.configData = new ConfigData();

7        //defaultMaxPerRoute默认为2,maxTotal默认为20

8        this.pool = new CPool(new InternalConnectionFactory(

9                this.configData, connFactory), 2, 20, timeToLive, tunit);

10        this.pool.setValidateAfterInactivity(2000);

11        this.connectionOperator = Args.notNull(httpClientConnectionOperator, "HttpClientConnectionOperator");

12        this.isShutDown = new AtomicBoolean(false);

13    }

所以当请求连接被占用2个后,后面的请求并不会获取到连接,这么说,我们需要释放连接资源。这里我们需要介绍EntityUtils这个类,里面包含了两个释放连接资源的方法consumeQuietly(HttpEntity entity)和consume(HttpEntity entity),前者内部也是请求后者完成关闭InputStream。调整后的代码如下:

1@Test

2    public void testHttpClient(){

3        for (int i = 0; i 

4            String url = "http://127.0.0.1:9092/learn/product/get/12";

5            HttpGet httpGet = new HttpGet(url);

6            HttpResponse res = null;

7            try {

8                res = client.execute(httpGet);

9            } catch (IOException e) {

10                log.error("异常: ", e);

11                return;

12            } finally {

13                if (null != res) {

14                    EntityUtils.consumeQuietly(res.getEntity());

15                }

16            }

17        }

18    }

调整完代码后,我们执行后发现5个请求都能正确请求并得到响应结果。或许有同学会问到如果我调整maxConnPerRoute和maxConnTotal不也行吗?可以,但是你的连接还是没有释放,当超过你设置值后也会出现无法获得连接池的问题。

被CloseableHttpClient名字所坑

最近项目中就是使用到CloseableHttpClient实现请求第三方,踩完上面的坑后,我们在项目中写了一个工厂类内部用枚举方式实现单例。经过并发测试后,的确没有出现上述坑,看了CloseableHttpClient有一个execute方法,最后也有释放资源,所以没有在意。直到今天写文章对应的测试案例我才发现我被这个方法欺骗了。

CloseableHttpClient的execute()重载了多个方法,而实际调用能释放资源的execute必须是包含ResponseHandler extends T>这个属性,否则和原有HttpClient方式是一样的。为何,模拟高并发下并没有发生问题呢?这是因为项目中请求响应结果后是用下面的代码完成数据获取的。

1 HttpResponse response = client.execute(get);

2 String res = EntityUtils.toString(response.getEntity());

跟进EntityUtils.toString()方法的最底层调用,会执行InputStream关闭流,和上文说的consume方法一样。但是这里坑就坑在,如果请求第三方超时或其他异常,则直接跳过,并没有执行上面的toString()方法,那就不会释放连接资源。

知道坑所在,要解决也就好办。可以有下述两个方案:

1、外层调用增加finally释放连接,上文所述。

2、实例化一个ResponseHandler对象,调用实现了释放连接资源的方法。

总结

今天我们一起学习了HttpClient和CloseableHttpClient没有正确释放连接,以及并发受限的问题。实际项目中如果没有考虑到这两个情况,则会带来生产问题,后面的请求一直无法获取到连接资源,以及并发量起不来。很多项目并不会有这个问题是因为HttpClient和CloseableHttpClient并不是单例的,每次使用都会是新的实例。希望通过今天的学习对你日后使用HttpClient更加得心应手。由于篇幅问题,没有把CloseableHttpClient案例放上来,有兴趣的同学可以到GitHub上下载(https://github.com/littleluo/bj-share-java.git)。

思考和讨论

1、案例中,我们使用了static和枚举的方式解决单例问题,除了这两种方法外,还有哪些方式呢?他们各自的优缺点是什么?

2、说回前面关于分布式锁的文章中,我们用到了redis,也提到client.close()方式归还连接,为何是归还连接,而不是关闭连接呢?

欢迎留言与我分享和指正!也欢迎你把这篇文章分享给你的朋友或同事,一起交流。

感谢您的阅读,我们下节再见!

扫码关注我们,与君共进

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UESTC_秋实大哥下棋 2015 UESTC Training for Data StructuresProblem I

I - 秋实大哥下棋 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit Status胜负胸中料已明,又从堂上出奇兵。秋实大哥是一个下棋好手,独孤求败的他觉得下棋已经无法满足他了,他开始研究一种新的…

java 6大原则_java 6大设计原则 一:观察者模式

解耦常用的模式OrderService.javaServicepublic class OrderService{AutowiredApplicationContext applicationContext ;public void saveOrder(){//1.创建订单System.out.println(“1.创建订单”);OrderEvent event new OrderEvent("参数")application…

jbb是什么梗_子水是什么意思,子水命理

子水是十二地支之一,那么命中有子水的代表的是什么呢?适合什么方位呢?有什么喜忌吗?怎么分析你呢?现在金宝贝起名网为你介绍子水是什么意思,子水命理的相关文章。子水是什么意思,子水命理八字地支:子水是什么意思1、对…

IOS高级编程之二:IOS的数据存储与IO

一、应用程序沙盒 IOS应用程序职能在系统为该应用所分配的文件区域下读写文件,这个文件区域就是应用程序沙盒。所有的非代码文件如:图片、声音、映象等等都存放在此。 在mac中command+shift+G命令,然后输入users/用户名…

安卓投屏大师_苹果,安卓手机如何免费投屏?只要悄悄按下这里,便能轻松实现...

现在很多手机都有自带投屏功能,这样一来我们便可以将所看的视频,所玩的游戏投屏到电脑或电视上了,当然也需要这些设备支持投屏才行。一、无线投屏1、苹果手机苹果手机的投屏功能在哪里呢?只要打开苹果手机从下往上滑动&#xff0c…

b站电脑客户端_如何将B站的flv格式的视频转换成mp4格式

经常看到B站有精彩的视频片段,于是想把这些视频下载保存到电脑,但是发现没有下载按钮,是不是很悲催。有些时候想从优酷、土豆网这些视频网站下载视频,结果却提示要先下载视频客户端才能继续下载视频,运气差的话&#x…

asp.net 设置 excel alignment_教你如何用Python轻轻松松操作Excel、Word、CSV,一文就够了,赶紧码住!!!...

作者:奈何缘浅wyjhttps://juejin.im/post/6868073137263607821Python 操作 Excel常用工具数据处理是 Python 的一大应用场景,而 Excel 又是当前最流行的数据处理软件。因此用 Python 进行数据处理时,很容易会和 Excel 打起交道。得益于前人的…

java 页面输出一个页面_java学习之:一个完整页面输出信息的过程(以输出Doctor表中信息为例)...

最近在练习java程序,总结一下从数据库查询信息并输出到jsp页面的过程。主要数据处理在src.cn.javatest包下面项目预览1,配置项目根目录src目录下的druid.properties数据库信息(相当于一个数据库配置文件)里面的信息可以在下载druid中获得,只需…

[xsd学习]xsd介绍

一直以来项目中对xml格式的判断使用的都是dtd格式,直到最近才发现,不知何时都已经转为xsd来进行判断和校验,于是今天专门找资料看下,不得不说,对于这类资料的入门,w3cschool真是个不错的资料库,…

教学目标四个维度_【深度好文】体育教案中的教学目标与学习目标应如何表述...

体育教师大本营教学/训练/职业/成长强 烈 建 议 大 家 星 标 我 们教 学 路 上 ☆ 不 离 不 弃在以往看到的体育课的教案上,目标部分不是用教学目标就是用学习目标来表述,然而,这两种目标表达形式有没有本质区别?分别该如何表述…

java中检查性异常类_Java异常处理、java语言推崇使用检查类型异常

异常处理是java语言的重要特性之一,《Three Rules for effective Exception Handling》一文中是这么解释的:它主要帮助我们在debug的过程中解决下面的三个问题。什么出错了哪里出错了为什么出错java语言可以说是提供了过于完善的异常处理机制&#xff0c…

nodejs readfilesync 路径_Linux 磁盘多路径聚合multipath

在日常工作中我们经常遇到配置存储的多路径聚合。多路径的目的是,当主机HBA卡、线缆、交换机或者存储设备的控制器故障等原因造成一条物理路径失效时,服务器可以将通过此物理路径的I/O转移到其他正常的物理路径上面,应用程序不会觉察到这种改变,从而提高…

u 20ubuntu 安装 postfix_极力推荐和田咨询问题U型钢托盘厂家

12极力推荐和田咨询问题U型钢托盘厂家泊头市毅伽属制品有限公司坐落于河北省泊头市龙华街北4公里,濒临京沪、石黄高速公路以及104、307国道,另有廊泊路贯穿南北交通十分便利。本公司设计生产各种冷弯型钢,产品包括C型钢、Z型钢、U型钢、M型钢…

HTML5中lineCap端点样式遇到closePath()

定义和用法 lineCap 属性设置或返回线条末端线帽的样式。 注释:"round" 和 "square" 会使线条略微变长。 默认值:buttJavaScript 语法:context.lineCap"butt|round|square";属性值 值描述butt默认。向线条的每…

php鼠标悬停显示图片,鼠标滑过出现预览的大图提示效果

当鼠标滑过图片时,图片会出现预览的大图,大图下面还会有介绍文字。.aa{width:88px;height :100px;}$(function () {var x 10;var y 20;$("a.tooltip").mouseover(function (e) {this.myTitle this.title;this.title "";var imgT…

405 not allowed什么意思_二驴质问散打:为什么不救天道!面临一个亿赔款?次惑小仙女宣布与可乐分手!...

次惑小仙女发作品表示:对不起让你们失望了,慢慢也学着长大了,懂得了很多,以前每天就知道天真傻笑的玩,后来懂得了努力和加油,但是很多东西并不是大家看到的那样背后的事情谁又能知道。都认为他对我很好,只有自己知道,呵呵。有些时…

hdu.1254.推箱子(bfs + 优先队列)

推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6021 Accepted Submission(s): 1718 Problem Description推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运…

ae合成设置快捷键_怎么在ae中剪切视频?怎么在ae里裁剪视频?

ae剪切裁剪视频教程:零基础学AE软件影视后期必修课程-AE新建合成-羽兔网​www.yutu.cn1、启动After Effects并导入视频第一个任务是打开一个新项目,并将视频加载到其中。首先从主菜单中选择新的构图。然后打开构图菜单,选择所需的分辨率等&am…

php js获取元素id,javascript通过中文id和class获取元素的方法

以前以为html元素中的id和class等只能通过字母数字或者下划线等特殊字符命名,如果单存使用中文浏览器不会报错,但是js是获取不到的,但是今天逛论坛的时候发现不是这样的。代码如下:运行结果:论坛来源是这个&#xff1a…

delphi random 六位_《蒙面唱将猜猜猜》第五季将播,六位唱将率先登场

原标题:《蒙面唱将猜猜猜》第五季将播,六位唱将率先登场新京报讯(记者 刘玮)《蒙面唱将猜猜猜》第五季将于11月1日21:10在江苏卫视首播,优酷视频全网独播。第五季中,猜评团不仅“觊觎”各路唱将的真实身份,…