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 提交代碼以後的幾種後悔藥