1. 程式人生 > 其它 >HikariCP原始碼簡潔剖析——FastList

HikariCP原始碼簡潔剖析——FastList

FastList是什麼

HikariCP中實現的一個List,底層基於陣列實現,目的是提高List操作的效能,主要用於HikariCP中快取Statement例項和連結。

與JDK自帶的ArrayList的主要優化:

  1. 去掉了addgetremove等操作時的範圍檢查。原始碼中FastList的註釋為:Fast list without range checking
  2. remove方法裡取值時從後向前遍歷

可以發現其實並沒有太高階的操作,但這就是HikariCP快的原因之一,將細節做到極致。

原始碼剖析

初始化

初始化時預設陣列長度為32。

ArrayList中預設陣列長度為10。

public FastList(Class<?> clazz)
   {
      //預設32個元素
      this.elementData = (T[]) Array.newInstance(clazz, 32);
      this.clazz = clazz;
   }

新增元素

  1. 新元素放在陣列的尾端
  2. 每次擴容時長度為舊陣列的兩倍
   /**
    * 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. 新元素放在陣列的尾端
  2. 每次擴容時長度為舊陣列的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&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;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();
}