COW
如果有多个调用者请求相同资源,他们会获得相同的指针指向同一个资源,知道某个调用者试图修改资源内容,系统才会真正复制一份专用副本给调用者,而其他调用者所见到的最初资源不变.
- 优点:如果不修改,就不会有副本建立
 - 缺点:
- 内存占用:如果CopyOnWriteArrayList经常要增删改里面的数据,经常要执行
add()、set()、remove()的话,那是比较耗费内存的。- 因为我们知道每次
add()、set()、remove()这些增删改操作都要复制一个数组出来。 
 - 因为我们知道每次
 - 数据一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
- 从上面的例子也可以看出来,比如线程A在迭代CopyOnWriteArrayList容器的数据。线程B在线程A迭代的间隙中将CopyOnWriteArrayList部分的数据修改了(已经调用
setArray()了)。但是线程A迭代出来的是原有的数据。 
 - 从上面的例子也可以看出来,比如线程A在迭代CopyOnWriteArrayList容器的数据。线程B在线程A迭代的间隙中将CopyOnWriteArrayList部分的数据修改了(已经调用
 
 - 内存占用:如果CopyOnWriteArrayList经常要增删改里面的数据,经常要执行
 
CopyOnWriteArrayList
- 线程安全
 - 底层通过复制数组实现
 - 遍历时候不会抛出ConcurrentModificationException异常
 - 元素可以为null
 
基本结构
/** 可重入锁对象 */final transient ReentrantLock lock = new ReentrantLock();/** CopyOnWriteArrayList底层由数组实现,volatile修饰 */private transient volatile Object[] array;/*** 得到数组*/final Object[] getArray() {return array;}/*** 设置数组*/final void setArray(Object[] a) {array = a;}/*** 初始化CopyOnWriteArrayList相当于初始化数组*/public CopyOnWriteArrayList() {setArray(new Object[0]);}
CopyOnWriteArrayList底层就是数组,加锁就交由ReentrantLock来完成。
add
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;// 将volatile Object[] array 的指向替换成新数组setArray(newElements);return true;} finally {lock.unlock();}}public int size() {// 直接得到array数组的长度return getArray().length;}public E get(int index) {return get(getArray(), index);}final Object[] getArray() {return array;}
- 上锁
 - 复制一个新的数字
 - 拷贝
 - 在末尾加上被添加的元素
 - 使元素指向新数组
 - 解锁
 
set
public E set(int index, E element) {final ReentrantLock lock = this.lock;lock.lock();try {// 得到原数组的旧值Object[] elements = getArray();E oldValue = get(elements, index);// 判断新值和旧值是否相等if (oldValue != element) {// 复制新数组,新值在新数组中完成int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len);newElements[index] = element;// 将array引用指向新数组setArray(newElements);} else {// Not quite a no-op; enssures volatile write semanticssetArray(elements);}return oldValue;} finally {lock.unlock();}}
- 加锁
 - 获取index位置的值
 - 如果值一样,不修改
 - 值不一样,复制新数组,设置数组指向
 - 解锁
 - 返回
 
遍历

// 1. 返回的迭代器是COWIteratorpublic Iterator<E> iterator() {return new COWIterator<E>(getArray(), 0);}// 2. 迭代器的成员属性private final Object[] snapshot;private int cursor;// 3. 迭代器的构造方法private COWIterator(Object[] elements, int initialCursor) {cursor = initialCursor;snapshot = elements;}// 4. 迭代器的方法...public E next() {if (! hasNext())throw new NoSuchElementException();return (E) snapshot[cursor++];}//.... 可以发现的是,迭代器所有的操作都基于snapshot数组,而snapshot是传递进来的array数组
可以发现的是,迭代器所有的操作都基于snapshot数组,而snapshot是传递进来的array数组
**
