http连接池

转自 :

最近学习了Http连接池 - 五月的仓颉 - 博客园


【1】使用线程池与否的程序性能

我的任务定义:从0 累加到 100w;

public class ThreadPoolMain {/*** 线程池测试*/private static final AtomicInteger THREAD_EXECUTED_TOTAL = new AtomicInteger(0); // 已执行线程总数private static final AtomicLong EXECUTE_COST_MS = new AtomicLong(0); // 执行耗时毫秒private static final Integer ACCUMULATED_SUM_UPPER = 1000000; // 单个任务累加和上限private static final Integer TASK_TOTAL = 1000; // 任务总计private class IncreaseThread implements Runnable {public void run() {long startTime = System.currentTimeMillis();AtomicInteger counter = new AtomicInteger(0);for (int i = 0; i < ACCUMULATED_SUM_UPPER; i++) {counter.incrementAndGet();}// 累加执行时间EXECUTE_COST_MS.addAndGet(System.currentTimeMillis() - startTime);if (THREAD_EXECUTED_TOTAL.incrementAndGet() == TASK_TOTAL) {System.out.println("cost: " + EXECUTE_COST_MS.get() + "ms");}}}

【1.1】方式1,不使用线程池

来一个任务,就开启线程运行它;

/*** 不使用线程池* 来一个任务,就开启线程运行它*/@Testpublic void testRunWithoutThreadPool() {List<Thread> tList = new ArrayList<Thread>(TASK_TOTAL);for (int i = 0; i < TASK_TOTAL; i++) {tList.add(new Thread(new IncreaseThread()));}for (Thread t : tList) {t.start();}for (;;);}
// cost: 2418156 ms 

【1.2】方式2,使用线程池

创建包含多个线程的线程池,来一个任务,从线程池中取出线程运行任务,而不是重新创建一个;

/*** 使用线程池*/@Testpublic void testRunWithThreadPool() {ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 0, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());for (int i = 0; i < TASK_TOTAL; i++) {executor.submit(new IncreaseThread());}for (;;);}
// cost: 27306 ms 

小结: 很显然,使用线程池后,运行任务的速度更快,性能更高

主要原因在于 方式1不使用线程池,创建线程成本累加起来非常高,耗费资源多,然后这些资源却没有真正执行业务逻辑计算;


【2】http连接池

1)http 运行架构

/*** 连接池基类*/
public class BaseHttpClientTest {protected static final int REQUEST_COUNT = 5;protected static final String SEPERATOR = "   ";protected static final AtomicInteger NOW_COUNT = new AtomicInteger(0);protected static final StringBuilder EVERY_REQ_COST = new StringBuilder(200);/*** 获取待运行的线程*/protected List<Thread> getRunThreads(Runnable runnable) {List<Thread> tList = new ArrayList<Thread>(REQUEST_COUNT);for (int i = 0; i < REQUEST_COUNT; i++) {tList.add(new Thread(runnable));}return tList;}/*** 启动所有线程*/protected void startUpAllThreads(List<Thread> tList) {for (Thread t : tList) {t.start();// 这里需要加一点延迟,保证请求按顺序发出去try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}}/*** 计算执行成本,包括耗时*/protected synchronized void addCost(long cost) {EVERY_REQ_COST.append(cost);EVERY_REQ_COST.append("ms");EVERY_REQ_COST.append(SEPERATOR);}
}

【2.1】方式1,不使用连接池发送http请求

/*** 不使用连接池测试*/
public class HttpWithoutPoolTest extends BaseHttpClientTest {@Testpublic void test() throws Exception {startUpAllThreads(getRunThreads(new HttpThread()));// 等待线程运行for (;;);}private class HttpThread implements Runnable {public void run() {/*** HttpClient是线程安全的,因此HttpClient正常使用应当做成全局变量,但是一旦全局共用一个,HttpClient内部构建的时候会new一个连接池* 出来,这样就体现不出使用连接池的效果,因此这里每次new一个HttpClient,保证每次都不通过连接池请求对端*/CloseableHttpClient httpClient = HttpClients.custom().build();HttpGet httpGet = new HttpGet("https://www.baidu.com/");long startTime = System.currentTimeMillis();try {CloseableHttpResponse response = httpClient.execute(httpGet);if (response != null) {response.close();}} catch (Exception e) {e.printStackTrace();} finally {addCost(System.currentTimeMillis() - startTime);if (NOW_COUNT.incrementAndGet() == REQUEST_COUNT) {System.out.println(EVERY_REQ_COST.toString());}}}}
}
// 460ms   461ms   462ms   462ms   462ms   

【2.2】方式2,使用连接池发送http请求

/*** 使用连接池测试*/
public class HttpWithPoolTest extends BaseHttpClientTest {private CloseableHttpClient httpClient = null;@Beforepublic void before() {initHttpClient();}@Testpublic void test() throws Exception {startUpAllThreads(getRunThreads(new HttpThread()));// 等待线程运行for (;;);}private class HttpThread implements Runnable {public void run() {HttpGet httpGet = new HttpGet("https://www.baidu.com/");// 长连接标识,不加也没事,HTTP1.1默认都是Connection: keep-alive的httpGet.addHeader("Connection", "keep-alive");long startTime = System.currentTimeMillis();try {CloseableHttpResponse response = httpClient.execute(httpGet);if (response != null) {response.close();}} catch (Exception e) {e.printStackTrace();} finally {addCost(System.currentTimeMillis() - startTime);if (NOW_COUNT.incrementAndGet() == REQUEST_COUNT) {System.out.println(EVERY_REQ_COST.toString());}}}}private void initHttpClient() {final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();// 总连接池数量connectionManager.setMaxTotal(1);// 可为每个域名设置单独的连接池数量connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.baidu.com")), 1);// setConnectTimeout表示设置建立连接的超时时间// setConnectionRequestTimeout表示从连接池中拿连接的等待超时时间// setSocketTimeout表示发出请求后等待对端应答的超时时间RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000).setConnectionRequestTimeout(2000).setSocketTimeout(3000).build();// 重试处理器,StandardHttpRequestRetryHandler这个是官方提供的,看了下感觉比较挫,很多错误不能重试,可自己实现HttpRequestRetryHandler接口去做HttpRequestRetryHandler retryHandler = new StandardHttpRequestRetryHandler();httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).setRetryHandler(retryHandler).build();// 服务端假设关闭了连接,对客户端是不透明的,HttpClient为了缓解这一问题,在某个连接使用前会检测这个连接是否过时,如果过时则连接失效,但是这种做法会为每个请求// 增加一定额外开销,因此有一个定时任务专门回收长时间不活动而被判定为失效的连接,可以某种程度上解决这个问题Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {try {// 关闭失效连接并从连接池中移除connectionManager.closeExpiredConnections();// 关闭30秒钟内不活动的连接并从连接池中移除,空闲时间从交还给连接管理器时开始connectionManager.closeIdleConnections(20, TimeUnit.SECONDS);} catch (Throwable t) {t.printStackTrace();}}}, 0 , 1000 * 5);}
}
// 346ms   205ms   184ms   167ms   169ms   

小结: 使用 http连接池发送请求的性能, 优于不使用http连接

更深层次原因,refer2

 最近学习了Http连接池 - 五月的仓颉 - 博客园

这张图特别有意思,可以看到发送请求与接收响应的详情

 

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

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

相关文章

Quartz定时任务的基本搭建

前言 个人地址&#xff1a;Quartz定时任务的基本搭建 Quartz是一个完全由Java编写的开源作业调度框架&#xff0c;为在java应用程序中进行作业调度提供了简单又强大的机制。 Quartz中分为几个核心概念&#xff1a; Job - 表示一个工作&#xff08;任务&#xff09;&#xff0…

matlab 定义一个有自变量的方程_常微分方程:(第四章) 高阶微分方程

参考《常微分方程》第三版&#xff08;王高雄&#xff09;常微分方程王高雄 第四章 高阶微分方程_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com对于高阶微分方程&#xff0c;线性部分见4、5章&#xff0c;非线性部分见6章。4.1 线性微分方程的一般理论定义&#xff…

HttpClient api-连接池

【README】 本文 refer2 HttpClient Tutorialhttps://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/pdf/httpclient-tutorial.pdf 【2.3】http连接管理器 【2.3.1】可管理的连接与连接管理器 1&#xff09;http连接简述 HTTP 连接是复杂的、有状态的、线程…

使用SpringBoot搭建一个简单的webSocket服务

前言 个人地址&#xff1a;使用SpringBoot搭建一个简单的webSocket服务 什么是WebSocket&#xff1f; WebSocket是一个HTML5新增的协议,它的目的在浏览器和服务器之间建立一个不受限的双向实时通信的通道。比如&#xff0c;服务器可以任意时刻发送消息给浏览器。它是基于TCP&am…

cas 登录之后不跳转_图解JWT如何用于单点登录

点击上方“Java知音”&#xff0c;选择“置顶公众号”技术文章第一时间送达&#xff01;作者&#xff1a;流云诸葛http://cnblogs.com/lyzg/p/6132801.html推荐阅读(点击即可跳转阅读)1. 淘宝服务端高并发分布式架构演进之路2. IntelliJ IDEA 从入门到上瘾教程&#xff0c;2019…

转:java网络编程-HTTP编程

转自&#xff1a; java网络编程-HTTP编程_Stillsings的博客-CSDN博客HTTP编程Java HTTP编程支持模拟成浏览器的方式去访问网页URL, Uniform Resource Locator&#xff0c;代表一个资源URLConnection获取资源连接器根据URL的openConnection&#xff08;&#xff09;方法获得URL…

Centos7-通过RPM方式安装MySQL5.7

前言 Hallo&#xff0c;我们都知道开发时数据库是不可或缺的&#xff0c;本文就简单记录一下安装MySQL数据库的其中一种方式吧。 系统环境 系统&#xff1a;CentOS Linux 7.5 数据库版本&#xff1a;5.7 安装步骤 1. 从官网获取安装包 官方下载地址&#xff1a;https://ww…

python开发工具下所有软件都打不开_Python 开发工具链全解

可能刚开始学习Python时&#xff0c;有人跟你说可以将源文件所在的文件夹添加到 PYTHONPATH环境变量中&#xff0c;然后可以从其他位置导入此代码。在大多数情况下&#xff0c;这个人常常忘记补充这是一个非常糟糕的主意。有些人在互联网上发现了这一点&#xff0c;其他人却要看…

利用F#库canopy进行UI测试

虽然Selenium是一个流行的UI测试库&#xff0c;但基于它创建的测试却有着脆弱与不可靠等常见的问题。InfoQ与canopy的作者Chris Holt进行了一次访谈&#xff0c;以便更深入地了解canopy这个在Selenium的基础上所创建的F#库。 InfoQ&#xff1a;你能否为我们介绍一下canopy&…

转: Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)

转自&#xff1a; Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解) - Java知音号 - 博客园RestTemplate是Spring提供的用于访问Rest服务的客户端&#xff0c;RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。 我之前的HTTP开发是…

SpringBoot整合Shiro权限框架

前言 在系统管理中&#xff0c;权限是非常重要的一个环节。目前权限框架中使用比较多的有Shiro、Spring Security。&#x1f383; 本篇简单写一下SpringBoot整合Shiro权限框架小栗子&#x1f330;。 个人博客地址&#xff1a;SpringBoot整合Shiro权限框架 介绍Shiro Apache S…

Java开发必须掌握的8种网站攻防技术

转载自 Java开发必须掌握的8种网站攻防技术 XSS攻击 XSS攻击的全称是跨站脚本攻击(Cross Site Scripting),是WEB应用程序中最常见到的攻击手段之一。跨站脚本攻击指的是攻击者在网页中嵌入恶意脚本程序, 当用户打开该网页时,脚本程序便开始在客户端的浏览器上执行,以盗取客户端…

转:json与map互转

转自&#xff1a; java中字符串&#xff0c;json&#xff0c;Map互相转换&#xff08;各种转换都有&#xff09;_蜗牛驿站-CSDN博客_java json转map前提&#xff1a;使用jar包为fastjsonimport com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject; 程序如下: …

专属微信二维码python制作_如何利用Python制作简单的公众号二维码关注图

创意配图&#xff1a;微信&#xff0c;微信公众号&#xff0c;微信大V 而且最近发现了一个新的图像处理方面的库—Wand&#xff0c;它是 ImageMagick 库的 Python 接口。于是&#xff0c;我就打算用这个库来实现简单的制作一个二维码关注图&#xff0c;主要是完成以下几个工作&…

如何迁移#SNMP到.NET Core平台的一些体会

.NET Core 依然在飞速进化中&#xff0c;所以如果不是非常喜欢折腾的性格&#xff0c;建议各位还是暂时忍耐。 准备阶段 首先&#xff0c;Visual Studio 2015是必要的开发工具。虽然它已经包含了.NET Core的原始测试版&#xff0c;这里还是推荐下载 RC1 安装包&#xff0c; htt…

JAVA实现一个图片上传预览功能

这个小项目主要使用java实现了一个简单的图片上传预览功能&#xff0c;废话不多说&#xff0c;先上实现成果 ^ _ ^&#x1f4af; 预览 登录页 主页 上传页 图片预览 项目架构 后端: SpringBoot shiro mybatis-plus druid hutool 前端: layui viewer 项目结构 ├─src├…

小程序执行运行过程原理_PLC的基础小知识!不用把PLC想的太难

PLC实质上是工业计算机&#xff0c;是计算机技术与传统继电接触器控制器技术相结合的产物&#xff0c;只不过比一般的计算机具有更强的与工业过程相连接的接口和更直接的适用于工业控制要求的编程语言。一、PLC的结构从硬件结构上看&#xff0c;PLC主要由中央处理单元(CPU)、存…

内部局域网可自行分配的ip地址

【1】有些ip地址很特殊 以 10. 、 172.16. 、172.31. 、192.168. 开头的所有ipv4地址都未分配。 更确切的说&#xff0c;这些地址不会被 ISP&#xff08;Internet服务提供商&#xff09;分配给广域网上的计算机&#xff0c;即无法加入全球Internet网络-广域网&#xff1b; 但…

以吃货的角度理解 IaaS,PaaS,SaaS 是什么

转载自 以吃货的角度理解 IaaS&#xff0c;PaaS&#xff0c;SaaS 是什么随着云计算时代的到来&#xff0c;越来越多的软件&#xff0c;开始采用云服务。越来越多的概念也随之而来。云服务只是一个统称&#xff0c;可以分成三大类。IaaS&#xff1a;基础设施服务&#xff0c;Inf…

.Net使用RabbitMQ详解

序言 这几天呢&#xff0c;公司风波再起&#xff0c;去年一年公司CTO换啦4任&#xff0c;CEO换啦三个&#xff0c;这不刚来个新老大&#xff0c;感觉还不错&#xff0c;却没干过3个月又要走&#xff0c;索性趁老大们走来走去的时候&#xff0c;就给自己空出来&#xff0c;稍稍总…