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