HikiriCP做为当今世界上最快的数据库链接池中间件,其对代码追求的极致一直被开源爱好者津津乐道。HikariCP之因此这么快的其中一个缘由就是:开发FastList取代ArrayList。那么FastList是个什么东西?相比ArrayList有哪些出色的地方?接下来让咱们经过对源码的分析来一探究竟。java
首先,让咱们打开HikariCP的源代码,若是你不想下载它的源码的话,你也能够只打开 https://github.com/brettwooldridge/HikariCP/blob/master/src/main/java/com/zaxxer/hikari/util/FastList.java 便可,就能看到FastList的源码。git
咱们首先看一下这个类的注释,以下所示。经过这段注释咱们能够得出几个结论,1. FastList并非彻底凭空造出来的而是基于ArrayList造出来的,正所谓站在巨人的肩膀上。2. 由这个类的注释咱们可知,它没有range checking,即范围检查。若是看过ArrayList的源码的话,咱们就知道,它的get()、set()、remove()等不少方法中都执行了范围检查(rangeCheck(index)):github
/** * 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)的,它并不须要这些方法。sql
addadd方法是一个很是有用、使用频率很高的方法。并且刚才咱们说了,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 code final 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&removeget也是使用频率极高的一个方法,那么FastList作了哪些优化了,请看源码。优化的地方很是清楚了,FastList假定绝大部分调用get方法的index是合法的,从而不进行范围检查。而ArrayList则须要先进行范围检查,再获取具体位置的值。咱们知道:不管什么语言编写的多么高性能的代码,只要有代码执行,就会有性能损耗。这也是FastList干掉范围检查的缘由,能快一点是一点:ide
/** * @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 提交代码以后的几种后悔药