MySQL InnoDB 事务隔离级别的实现原理,linux 群集部署架构
1 /**
2 * Appends the specified element to the end of this list.
3 *
4 * @param e element to be appended to this list
5 * @return <tt>true</tt> (as specified by {@link Collection#add})
6 */
7public boolean add(E e) {
8 ensureCapacityInternal(size + 1); // Increments modCount!!
9 elementData[size++] = e;
10 return true;
11}
该方法是在集合中追加元素。其中核心方法是 ensureCapacityInternal,意思是确定集合内部容量。
1private void ensureCapacityInternal(int minCapacity) {
2 ensureExplicitCapacity(
3 calculateCapacity(elementData,minCapacity));
4}
5
6private static int calculateCapacity(Object[] elementData, int
7 minCapacity) {
8 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
9 return Math.max(DEFAULT_CAPACITY, minCapacity);
10 }
11 return minCapacity;
12}
这里首先计算了集合的容量,如果这个 ArrayList 是通过无参构造创建的,那么比较默认值 10,以及传入的 minCapacity,取最大值,这里可能有的同学会有疑问,为什么要比较默认值和 minCapacity,默认值不是一定大于 minCapacity 吗?,这里是因为 ensureCapacityInternal 这个方法不仅仅是 add()会调用,allAll()也会调用。
1public boolean addAll(int index, Collection<? extends E> c) {
2 rangeCheckForAdd(index);
3
4 Object[] a = c.toArray();
5 int numNew = a.length;
6 ensureCapacityInternal(size + numNew); // Increments modCount
7 //省略部分代码..
8 }
这里如果 numNew 大于 10,那么默认值就会不够用。所以才会在 calculateCapacity 方法中引入一个求最大值的步骤。
算出集合存储数据所需的最小空间后,就要考虑,集合原有存储空间是否够用,是否需要扩容。
1private void ensureExplicitCapacity(int minCapacity) {
2 modCount++;
3 // overflow-conscious code
4 if (minCapacity - elementData.length > 0)
5 grow(minCapacity);
6}
7
8/**
9 * Increases the capacity to ensure that it can hold at least the
10 * number of elements specified by the minimum capacity argument.
11 *
12 * @param minCapacity the desired minimum capacity
13 */
14 private void grow(int minCapacity) {
15 // overflow-conscious code
16 int oldCapacity = elementData.length;
17 int newCapacity = oldCapacity + (oldCapacity >> 1);
18 if (newCapacity - minCapacity < 0)
19 newCapacity = minCapacity;
20 if (newCapacity - MAX_ARRAY_SIZE > 0)
21 newCapacity = hugeCapacity(minCapacity);
22 // minCapacity is usually close to size, so this is a win:
23 elementData = Arrays.copyOf(elementData, newCapacity);
24}
这里我们
主要关注 4 个点:
1.int newCapacity = oldCapacity + (oldCapacity >> 1);每次扩容是原数组的 1.5 倍
2.扩容也是有限的,存在最大值:MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
3.集合扩容底层调用的是:Arrays.copyOf()方法,需要把数组中的数据复制一份,到新数组中,而这个方法底层是 System.arrayCopy 是一个 native 方法,效率不高。
4.最重要的一个点:如果我们可以事先估计出数据量,那么最好给 ArrayList 一个初始值,这样可以减少其扩容次数,从而省掉很多次内存申请和数据搬移操作。(不指定初始值,至少会执行一次 grow 方法,用于初始化内部数组)。
3.remove()
1/**
2 * Removes the element at the specified position in this list.
3 * Shifts any subsequent elements to the left (subtracts one from their
4 * indices).
5 *
6 * @param index the index of the element to be removed
7 * @return the element that was removed from the list
8 * @throws IndexOutOfBoundsException {@inheritDoc}
9 */
10public E remove(int index) {
11 rangeCheck(index);
12 modCount++;
13 E oldValue = elementData(index);
14
15 int numMoved = size - index - 1;
16 if (numMoved > 0)
17 System.arraycopy(elementData, index+1, elementData, index,
18 numMoved);
19 elementData[--size] = null; // clear to let GC do its work
20 return oldValue;
21}
删除的代码因为不涉及到缩容,所以比起 add 较为简单,首先会检查数组是否下标越界,然后会获取指定位置的元素,接着进行数据的搬移,将--size 位置的元素置成 null,让 GC 进行回收。最后将目标元素返回即可。
另外最后我想提出一个比较容易犯的错误,集合在遍历的时候,对其结构进行修改(删除、新增元素)。举一个例子:
1public class Test {
2 public static void main(String[] args) {
3 List<Integer> list = new ArrayList<>();
4 list.add(1);
5 list.add(2);
6 list.add(3);
7 for (Integer i : list) {
8 if(i.equals(1)){
9 list.remove(i);
10 }
11 }
12 }
13}
结果:
评论