HikariCP爲何本身造了一個FastList?

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

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 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&remove

get也是使用頻率極高的一個方法,那麼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 提交代碼以後的幾種後悔藥

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索