HikariCP为什么自己造了一个FastList?
HikiriCP作为当今世界上最快的数据库连接池中间件,其对代码追求的极致一直被开源爱好者津津乐道。HikariCP之所以这么快的其中一个原因就是:开发FastList取代ArrayList。那么FastList是个什么东西?相比ArrayList有哪些出色的地方?接下来让我们通过对源码的分析来一探究竟。
首先,让我们打开HikariCP的源代码,如果你不想下载它的源码的话,你也可以只打开 https://github.com/brettwooldridge/HikariCP/blob/master/src/main/java/com/zaxxer/hikari/util/FastList.java 即可,就能看到FastList的源码。
我们首先看一下这个类的注释,如下所示。通过这段注释我们可以得出几个结论,1. FastList并不是完全凭空造出来的而是基于ArrayList造出来的,正所谓站在巨人的肩膀上。2. 由这个类的注释我们可知,它没有range checking,即范围检查。如果看过ArrayList的源码的话,我们就知道,它的get()、set()、remove()等很多方法中都执行了范围检查(rangeCheck(index)):
/*** Fast list without range checking.** @author Brett Wooldridge*/
public final class FastList<T> extends ArrayList<T>
{... ...
}
我们现在大概知道了FastList相比ArrayList的改进,下面列举出两个类具体对比如下表格所示:
操作 | FastList | ArrayList |
---|---|---|
add | 重写 | 支持 |
get | 重写 | 支持 |
removeLast | 支持 | 不支持 |
remove(Object) | 重写 | 支持 |
clear | 重写 | 支持 |
size | 一样 | 一样 |
isEmpty | 一样 | 一样 |
set | 重写 | 支持 |
remove(int) | 重写 | 支持 |
iterator | 重写 | 支持 |
toArray、containsAll、contains、addAll、removeAll... ... | throw new UnsupportedOperationException() | 支持 |
精简部分
如上表格可知,FastList相比ArrayList,它屏蔽了很多它不需要的操作方法,例如:toArray、containsAll、contains、addAll、removeAll... ... 。只要调用这些方法,就会抛出UnsupportedOperationException异常。这是因为,FastList是HikariCP用来管理Statement(例如PrepareStatement)的,它并不需要这些方法。
add
add方法是一个非常有用、使用频率很高的方法。而且刚才我们说了,HikariCP是用FastList用来管理Statement的,这就意味着,在我们使用拿出数据库连接执行SQL时,都需要创建Statement,这就需要调用FastList的add()方法,所以这个方法是一个非常高频的方法。FastList的add()源码如下。它和ArrayList最大的区别是,FastList假设大部分情况下不需要扩容,直接给数据最后一个元素赋值即可。而ArrayList恰恰相反,需要先确保容量足够:
public boolean add(T element)
{try {elementData[size++] = element;}catch (ArrayIndexOutOfBoundsException e) {// overflow-conscious codefinal int oldCapacity = elementData.length;final int newCapacity = oldCapacity << 1;@SuppressWarnings("unchecked")final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity);System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);newElementData[size - 1] = element;elementData = newElementData; }return true;
}
FastList的add方法与ArrayList相比还有一点不同,FastList需要扩容时,通过左移一位来实现成倍扩容(final int newCapacity = oldCapacity << 1),而ArrayList每次都是1.5倍扩容(int newCapacity = oldCapacity + (oldCapacity >> 1))。很明显FastList的扩容少了一次+操作,性能更高。
get&set&remove
get也是使用频率极高的一个方法,那么FastList做了哪些优化了,请看源码。优化的地方非常清楚了,FastList假定绝大部分调用get方法的index是合法的,从而不进行范围检查。而ArrayList则需要先进行范围检查,再获取具体位置的值。我们知道:无论什么语言编写的多么高性能的代码,只要有代码执行,就会有性能损耗。这也是FastList干掉范围检查的原因,能快一点是一点:
/*** @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid*/
@Override
public T get(int index)
{// ArrayList需要先调用rangeCheck(index)进行范围检查return elementData[index];
}
set方法以及remove(int)方法和get方法进行了完全一样的优化,去掉了范围检查,它们都假定操作的index是完全合法的,只要每次操作的index完全有效,那么范围检查就是多余的,就可以通过干掉范围检查来提高性能。
removeLast
这是FastList新增的一个方法,ArrayList是没有这个方法的。为什么HikariCP新增了一个这样的方法呢?我们知道,在获取数据库连接执行SQL时,如果创建了多个Statement,那么后创建的Statement需要先关闭。以3个Statement为例,我们依次创建了stmt1,stmt2,stmt3。那么良好的编程习惯是先执行stmt3.close(),再stmt2.close(),最后stmt1.close()。而HikiriCP是用FastList管理Statement这个过程中实际调用了3次add()方法,然后依次调用3次removeLast方法,这就是为什么HikariCP需要造一个removeList方法的原因:
public T removeLast()
{T element = elementData[--size];elementData[size] = null;return element;
}
size&isEmpty
这两个方法FastList都没有进行任何优化,和ArrayList是一样的。
总结
现在知道HikariCP为什么要这样做了吧?这是因为,HikariCP的FastList和JDK中的ArrayList定位不一样,ArrayList是提供给无数使用JDK的用户使用的,所以,它的使用环境非常恶劣,那么它必须做各种合法性的检查。而FastList是HikariCP用来管理Statement的,是给它自己使用的,是特定场景下为了性能极致优化而造出来的一个东西,它只适用于这样特定的场景。
DD自研的沪牌代拍业务,点击直达
往期推荐
Spring Boot 2.4.0 正式发布!全新的配置处理机制,拥抱云原生!
服务网格仍然很难
10道棘手的Java面试题,看看你能答对几个?
如果MySQL磁盘满了,会发生什么?
Mysql 都会遭受哪些方面的攻击?
Git 提交代码之后的几种后悔药
扫一扫,关注我
一起学习,一起进步
每周赠书,福利不断
﹀
﹀
﹀
深度内容
推荐加入
HikariCP为什么自己造了一个FastList?相关推荐
- 干掉ArrayList:HikariCP为什么自己造了一个FastList?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! HikiriCP作为当今世界上最快的数据库连接池中间件,其 ...
- python数据校验_最近抽空造了一个数据校验的轮子 Python -validator
最近抽空造了一个数据校验的轮子 python-validator. 在开发 web 应用时,经常需要校验前端传入的数据.如果使用 Django,那么可以使用自带的 forms 进行数据校验. pyth ...
- 用php造了一个地址自动识别功能
用php造了一个地址自动识别功能 地址自动识别现在普遍,特别是用在快递填写地址,姓名,手机号码的时候,会把这些按照一定的规范填写后,点击自动识别后,会自动填写到各自的input.最近也简单的实现了这个 ...
- 转型下沉的51talk 能否在在线教育“造”出一个拼多多?
51talk自上市以来,一直处于亏损当中,但12月9日公布的财报显示,主营菲教一对一业务的似乎为其带来了新看点. 数据显示,1对1业务首次实现Non-GAAP盈利,其Non-GAAP净利润为270万, ...
- 从零造的一个网络轮子
从零造的一个网络轮子 序 大概是一些碎碎念 一 类图及各类简述 二 各个类详述及部分代码 2.1.main() & FairySunOfNetBaseStart() & Fairy ...
- 【AI简报20220211期】硬核UP主自己造了一个激光雷达、详解AI加速器
嵌入式AI 详解AI加速器(一):2012年的AlexNet到底做对了什么? 原文: https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid ...
- 真正的全栈工程师!B站硬核UP主自己造了一个激光雷达
机器之心报道 机器之心编辑部 转载自:机器之心 从零造一个激光雷达,需要多久? 激光雷达(LiDAR)是激光探测及测距系统的简称,目前广泛应用在无人驾驶和扫地机器人等领域.这种广泛的应用一方面得益于激 ...
- 苏宁不蹭618,造了一个“宝宝节”
6月1日凌晨1点,苏宁易购六一宝宝节开心直播夜全网观看量破1.6亿,这一"宝宝节"为当下电商平台的营销方式带来怎样的思考? 如今,双十一.618.818等促销节点已经列入到人们一年 ...
- 下沉市场中的元宇宙:我们造了一个“虚拟贫民窟”?
"web2.0的时候,我们追求资讯共享.跨越地域和种族的交流,web3.0的时候,我们发行货币,模拟娱乐,复制一个消费至死的地球,你们管这堆虚拟世界的玩具叫元宇宙?" 在探访元宇 ...
最新文章
- 一文读懂生物医学领域的传感器
- MySQL第1天:整体目录
- GitHub如何删除一个repository(仓库)
- 六十、第一个SpringBoot的 helloworld程序
- 阿里巴巴港股股价创历史新高 市值超6.1万亿港元
- 【Kafka】Kafka 使用传统的 avro API 自定义序列化类和反序列化类
- @扎克伯格:一句对不起,能挽回我们泄漏的数据吗?
- HDU2032 杨辉三角【入门】
- 如何在 Mac 上阻止 FaceTime 通话和 iMessage 信息?
- vmware安装安卓android详教程,虚拟机安装安卓系统教程
- 【装修大营救】装修失误郁闷到要吐血、追悔莫及:水电改、刷墙、橱柜
- 美国生活第二个月照片(2)
- 到底什么是类脑计算?
- elasticsearch查询之图书智能推荐
- Windows下安装pycocotools(本人亲测,可以解决)
- 一遍两遍三四遍,知识含义清晰现
- ARAP重分类:扪心自问,细节处你真的懂我吗?
- linux玩大型游戏下载软件,5个最受欢迎Linux版大型FPS游戏
- 上海腾科教育干货分享之达梦数据库培训课程DCP
- 《地球毁灭日》5希望号诺亚方舟
热门文章
- 自定义的GridView控件源代码
- Linux系统中FTP的配置(图文详解-全)
- linux centos 使用 alpine 编译的二进制文件 报错 /lib/ld-musl-x86_64.so.1: bad ELF interpreter 解决方法
- linux centos7 开机自动登录
- pycharm 远程调试
- linux 64平台上编译32位程序: GCC编译选项 -m64 -m32 -mx32
- shell公共函数:/etc/init.d/functions
- 深度学习与计算机视觉系列(4)_最优化与随机梯度下降\数据预处理,正则化与损失函数
- mysql 5.5 5.6差异,MySQL5.5和MySQL5.6授权区别
- php 输出 cvs,php将数组转换成cvs格式并输出的简单示例