HikariCP contains many micro-optimizations that individually are barely measurable, but together combine as a boost to overall performance. Some of these optimizations are measured in fractions of a millisecond amortized over millions of invocations.
其中第一条就提到了ArrayList的优化
One non-trivial (performance-wise) optimization was eliminating the use of an ArrayList instance in the ConnectionProxy used to track open Statement instances. When a Statement is closed, it must be removed from this collection, and when the Connection is closed it must iterate the collection and close any open Statement instances, and finally must clear the collection. The Java ArrayList, wisely for general purpose use, performs a range check upon every get(int index) call. However, because we can provide guarantees about our ranges, this check is merely overhead.
Additionally, the remove(Object) implementation performs a scan from head to tail, however common patterns in JDBC programming are to close Statements immediately after use, or in reverse order of opening. For these cases, a scan that starts at the tail will perform better. Therefore, ArrayList was replaced with a custom class FastList which eliminates range checking and performs removal scans from tail to head.
/** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index){ rangeCheck(index); return elementData(index); }
我们可以看到每次get的时候都会进行rangeCheck
/** * Checks if the given index is in range. If not, throws an appropriate * runtime exception. This method does *not* check if the index is * negative: It is always used immediately prior to an array access, * which throws an ArrayIndexOutOfBoundsException if index is negative. */ privatevoidrangeCheck(int index){ if (index >= size) thrownew IndexOutOfBoundsException(outOfBoundsMsg(index)); }
/** * 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的remove(Object)方法
/** * 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 */ publicbooleanremove(Object o){ if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); returntrue; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); returntrue; } } returnfalse; }
再对比看一下FastList的remove(Object方法)
/** * 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 publicbooleanremove(Object element) { for (int index = size - 1; index >= 0; index--) { if (element == elementData[index]) { finalint numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index + 1, elementData, index, numMoved); } elementData[--size] = null; returntrue; } } returnfalse; }
好了,今天的文章就是这么简短,最后附一下FastList的源码,内容真的是十分精简的。
/* * Copyright (C) 2013, 2014 Brett Wooldridge * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.zaxxer.hikari.util; import java.io.Serializable; import java.lang.reflect.Array; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; import java.util.Spliterator; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; /** * Fast list without range checking. * * @author Brett Wooldridge */ publicfinalclassFastList<T> implementsList<T>, RandomAccess, Serializable { privatestaticfinallong serialVersionUID = -4598088075242913858L; privatefinal Class<?> clazz; private T[] elementData; privateint size; /** * Construct a FastList with a default size of 32. * @param clazz the Class stored in the collection */ @SuppressWarnings("unchecked") publicFastList(Class<?> clazz) { this.elementData = (T[]) Array.newInstance(clazz, 32); this.clazz = clazz; } /** * Construct a FastList with a specified size. * @param clazz the Class stored in the collection * @param capacity the initial size of the FastList */ @SuppressWarnings("unchecked") publicFastList(Class<?> clazz, int capacity) { this.elementData = (T[]) Array.newInstance(clazz, capacity); this.clazz = clazz; } /** * Add an element to the tail of the FastList. * * @param element the element to add */ @Override publicbooleanadd(T element) { if (size < elementData.length) { elementData[size++] = element; } else { // overflow-conscious code finalint oldCapacity = elementData.length; finalint newCapacity = oldCapacity << 1; @SuppressWarnings("unchecked") final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity); System.arraycopy(elementData, 0, newElementData, 0, oldCapacity); newElementData[size++] = element; elementData = newElementData; } returntrue; } /** * 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]; } /** * Remove the last element from the list. No bound check is performed, so if this * method is called on an empty list and ArrayIndexOutOfBounds exception will be * thrown. * * @return the last element of the list */ public T removeLast() { T element = elementData[--size]; elementData[size] = null; return element; } /** * 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 publicbooleanremove(Object element) { for (int index = size - 1; index >= 0; index--) { if (element == elementData[index]) { finalint numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index + 1, elementData, index, numMoved); } elementData[--size] = null; returntrue; } } returnfalse; } /** * Clear the FastList. */ @Override publicvoidclear() { for (int i = 0; i < size; i++) { elementData[i] = null; } size = 0; } /** * Get the current number of elements in the FastList. * * @return the number of current elements */ @Override publicintsize() { return size; } /** {@inheritDoc} */ @Override publicbooleanisEmpty() { return size == 0; } /** {@inheritDoc} */ @Override public T set(int index, T element) { T old = elementData[index]; elementData[index] = element; return old; } /** {@inheritDoc} */ @Override public T remove(int index) { if (size == 0) { returnnull; } final T old = elementData[index]; finalint numMoved = size - index - 1; if (numMoved > 0) { System.arraycopy(elementData, index + 1, elementData, index, numMoved); } elementData[--size] = null; return old; } /** {@inheritDoc} */ @Override publicbooleancontains(Object o) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Iterator<T> iterator() { returnnew Iterator<T>() { privateint index; @Override publicbooleanhasNext() { return index < size; } @Override public T next() { if (index < size) { return elementData[index++]; } thrownew NoSuchElementException("No more elements in FastList"); } }; } /** {@inheritDoc} */ @Override public Object[] toArray() { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public <E> E[] toArray(E[] a) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleancontainsAll(Collection<?> c) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleanaddAll(Collection<? extends T> c) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleanaddAll(int index, Collection<? extends T> c) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleanremoveAll(Collection<?> c) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleanretainAll(Collection<?> c) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicvoidadd(int index, T element) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicintindexOf(Object o) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicintlastIndexOf(Object o) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public ListIterator<T> listIterator() { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public ListIterator<T> listIterator(int index) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public List<T> subList(int fromIndex, int toIndex) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Object clone() { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicvoidforEach(Consumer<? super T> action) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public Spliterator<T> spliterator() { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicbooleanremoveIf(Predicate<? super T> filter) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicvoidreplaceAll(UnaryOperator<T> operator) { thrownew UnsupportedOperationException(); } /** {@inheritDoc} */ @Override publicvoidsort(Comparator<? super T> c) { thrownew UnsupportedOperationException(); } }