HikariCP原始碼簡潔剖析——FastList
阿新 • • 發佈:2022-02-10
FastList是什麼
HikariCP中實現的一個List,底層基於陣列實現,目的是提高List操作的效能,主要用於HikariCP中快取Statement
例項和連結。
與JDK自帶的ArrayList的主要優化:
- 去掉了
add
、get
、remove
等操作時的範圍檢查。原始碼中FastList的註釋為:Fast list without range checking
remove
方法裡取值時從後向前遍歷
可以發現其實並沒有太高階的操作,但這就是HikariCP快的原因之一,將細節做到極致。
原始碼剖析
初始化
初始化時預設陣列長度為32。
ArrayList
中預設陣列長度為10。
public FastList(Class<?> clazz)
{
//預設32個元素
this.elementData = (T[]) Array.newInstance(clazz, 32);
this.clazz = clazz;
}
新增元素
- 新元素放在陣列的尾端
- 每次擴容時長度為舊陣列的兩倍
/** * Add an element to the tail of the FastList. * * @param element the element to add */ @Override public boolean add(T element) { try { //不檢查陣列空間是否充足,直接賦值,如果資料越界,再執行陣列擴容 elementData[size++] = element; } catch (ArrayIndexOutOfBoundsException e) { 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; }
作為對比,看下ArrayList
中的add
方法:
- 新元素放在陣列的尾端
- 每次擴容時長度為舊陣列的1.5倍
public boolean add(E e) {
//檢查陣列空間是否充足,若空間不足,執行擴容操作,新資料是舊陣列的1.5倍
ensureCapacityInternal(size + 1); // Increments modCount!!
//同樣是尾插
elementData[size++] = e;
return true;
}
查詢元素
不做範圍檢查,直接返回陣列下標。
在HikariCP中,FastList
用於儲存Statement和連結,程式可以保證FastList
/**
* Get the element at the specified index.
*
* @param index the index of the element to get
* @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid
*/
@Override
public T get(int index)
{
return elementData[index];
}
同樣看下ArrayList裡的get方法
public E get(int index) {
//先做範圍檢查,如果陣列越界,丟擲IndexOutOfBoundsException
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
return (E) elementData[index];
}
刪除元素
remove
裡在查詢元素時是從後向前遍歷的,原因還是FastList用來儲存Statement
,而Statement通過是後創建出來的先被Close掉,這樣可以提高查詢效率。
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
*@param element the element to remove
*/
@Override
public boolean remove(Object element)
{
//從後往前遍歷
for (int index = size - 1; index >= 0; index--) {
//基於==做比較而不是equals
if (element == elementData[index]) {
final int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null;
return true;
}
}
return false;
}
同樣看下ArrayList中的Remove方法:
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If the list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns <tt>true</tt> if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
//從前向後遍歷,找到第一個匹配的資料就結束
for (int index = 0; index < size; index++)
//null使用==判斷
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
//非null使用equals判斷
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
其他方法
FastList
實現了List
介面,但並沒有將所有方法都實現出來,對HikariCP中用不到的方法直接丟擲了UnsupportedOperationException
@Override
public <E> E[] toArray(E[] a)
{
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends T> c)
{
throw new UnsupportedOperationException();
}