CopyOnWriteArrayList是JAVA中的并发容器类,同时也是符合写时复制思想的CopyOnWrite容器。写时复制思想便是当咱们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,而后新的容器里添加元素,添加完元素以后,再将原容器的引用指向新的容器。这样作的好处是咱们能够对CopyOnWrite容器进行并发的读,而不须要加锁,由于当前容器不会添加任何元素。因此CopyOnWrite容器也是一种读写分离的思想,读和写不一样的容器。java
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
CopyOnWriteArrayList实现了List和RandomAccess接口,使得该容器能够具备列表的基本功能和随机访问的特性,而且实现了Cloneable接口和Serializable接口,表示可被克隆和序列化。数组
//重入锁 final transient ReentrantLock lock = new ReentrantLock(); //对象数组,用于存放数据,用volatile修饰 private transient volatile Object[] array;
//设置数组 final void setArray(Object[] a) { array = a; } //调用setArray,建立一个空的列表 public CopyOnWriteArrayList() { setArray(new Object[0]); } //建立一个包含collection的列表 public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; //判断集合C的类型是不是CopyOnWriteArrayList,若是是则获取集合的数组,不然进入else if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray();//将集合转为数组 //判断elements的类型是否为Object[]类型,若是不是则转为Object[]类型 if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); } setArray(elements);//设置数组 }
//将toCopyIn转为Object[]类型,而后设置数组
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
private E get(Object[] a, int index) { return (E) a[index]; } public E get(int index) { return get(getArray(), index); }
final Object[] getArray() { return array; }
get方法没有加锁也没有cas操做,所以代码很是简单。并发
//将指定元素添加到列表尾部 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;//添加元素e setArray(newElements);//设置数组 return true; } finally { lock.unlock();//释放锁 } }
//替换列表指定位置的元素 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;//替换指定位置的元素 setArray(newElements);//设置数组 } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue;//返回旧值 } finally { lock.unlock();//释放锁 } }
//删除指定位置的元素 public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index);//获取指定位置的元素 int numMoved = len - index - 1;//须要移动的元素个数 if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1));//移动个数为0则表示移除的是数组的最后一个元素,复制elements数组,复制长度为length-1,而后设置数组 else {//移动个数不为0 Object[] newElements = new Object[len - 1];//建立一个新数组 System.arraycopy(elements, 0, newElements, 0, index);//复制index以前的元素 System.arraycopy(elements, index + 1, newElements, index, numMoved);//复制index以后的元素 setArray(newElements);//设置数组 } return oldValue; } finally { lock.unlock(); } }
对于CopyOnWriteArrayList容器来讲,只适合读多写少的并发场景下使用。dom