学习目标

  1. 掌握ArrayList的扩容机制。
  2. 掌握Iterator的fail-fast和fail-safe机制。

扩容机制:

  1.  使用ArraryList()无参构造的时候,会使用长度为0的数组。
  2.  使用ArrayList(int initialCapacity)构造时,会使用指定容量的数组。 
  3.  使用public ArrayList(Colection<?   extends E> c)的时候,会使用c的大小作为数组容量。 
  4.  使用ArrayList 调用add(Object    o)方法,首次扩容会从0扩容成10,再次扩容会扩容到上一次容量的1.5倍,比如0,10,15,22,33…….
  5.  调用addAll(Colection  c)方法时,当前没有元素(容量为0的话),首次扩容会max(10,实际元素个数)(从10和实际加入元素个数中选择最大容量进行扩容),当前存在有元素时,则max(原容量1.5倍,实际元素个数)

fail-fast和fail-safe机制

文字说明:

  1. fail-fast:一旦发现遍历的同时其他人来修改,立即抛出错误(ConcurrentModificationExecption)
  2. fail-safe:发现便利的同时其他人来修改,应当有应对策略,比如牺牲数据一致性保证遍历的正常执行。

fail-fast的实现原理

当进行ArrayList遍历的时候,会先创建一个迭代器。 

Java ArrayList的扩容机制 arraylist 的扩容机制吧_java

Java ArrayList的扩容机制 arraylist 的扩容机制吧_实现原理_02

其中,cursor为下一个元素的返回值,lastRet为最后一个元素的索引,-1表示结束。

modCount是集合被修改的次数。

expectedModCount为迭代器修改次数,迭代器初始化时会等于modCount。

当迭代器执行next()时,会调用一个CheckForComdification()方法判断,这个方法会比较expectedModCount和modCount的值,如果两者不相等,证明集合在遍历期间元素发生了修改,这时候会抛出ConcurrentModificationException异常。

fail-safe的实现原理

当CopyOnWriteArrayList进行遍历的时候,会先创建一个迭代器。

Java ArrayList的扩容机制 arraylist 的扩容机制吧_实现原理_03

 这个时候,会现将原来的数组复制一份放至snapshot中。

Java ArrayList的扩容机制 arraylist 的扩容机制吧_Java ArrayList的扩容机制_04

 cursor是遍历时的元素下标,当cursor <snapshot.length时,表明仍有下一个元素,也就是hashNext方法的实现原理。

Java ArrayList的扩容机制 arraylist 的扩容机制吧_java_05

CopyOnWriteArrayList在添加元素的时候,是先获取当前的元素,然后List大小加1,将新元素放入其中。

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

但是,CopyOnWriteArrayList在遍历的时候,是对snapshot进行遍历,所以遍历的时候List的元素发生了改变,并不会对当前遍历造成影响,因此也不会报错。

Java ArrayList的扩容机制 arraylist 的扩容机制吧_迭代器_06

总结

1.ArrayList就是fail-fast典型的代表,遍历的同时不能修改,一旦发生修改则尽快失败。

2.CopyOnWriteArrayList是fail-last的典型代表,遍历时同时可以修改,原理是读写分离