1. 程式人生 > 程式設計 >CopyOnWriteArrayList 原始碼解析及使用場景

CopyOnWriteArrayList 原始碼解析及使用場景

基礎知識

待施工

  • Serializable
  • Cloneable
  • Iterable
  • Collection
  • List
  • RandomAccess

Java Doc 正文

這是一個執行緒安全的ArrayList,因為所有的修改操作都會複製一遍內部的陣列。 這個複製操作一般情況下是很昂貴的,但是在遍歷操作遠遠大於修改操作時,這個List還是很有效率的。

這個快照風格的迭代方法在迭代器建立時使用一個引用去記錄內部陣列的state。這個陣列在迭代過程中永遠都不會改變,所以迭代器永遠都不會丟擲 ConcurrentModificationException。你使用迭代器對list進行修改操作是無效的,會丟擲UnsupportedOperationException異常。 所有的元素都是允許的,包括null。

構造器

public CopyOnWriteArrayList()

建立一個空的list

public CopyOnWriteArrayList(Collection<? extends E> c)

建立一個CopyOnWriteArrayList包含引數集合的元素,元素的順序取決於引數集合的迭代器。 如果引數c為空null,會丟擲NPE

public CopyOnWriteArrayList(E[] toCopyIn)

建立一個CopyOnWriteArrayList包含引數陣列中的元素。引數資料為null就丟擲NPE

原始碼解析


package java.util.concurrent;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import sun.misc.SharedSecrets;


public class CopyOnWriteArrayList<E>
    implements List<E>,RandomAccess,Cloneable,java.io.Serializable {
    private static final long serialVersionUID = 8673264195747942595L;

    /** 可重入鎖,用來同步所有修改操作 */
    final transient ReentrantLock lock = new ReentrantLock();

    /** 元素陣列 */
    private transient volatile Object[] array;
    //下面兩個方法,get和set
Array,是CopyOnWriteArrayList的核心 //陣列複製後,使用set方法重新將引用設定成新的陣列,舊的陣列 //在其他執行緒迭代結束後就被JVM回收了 /** * 這個方法十分重要 */ final Object[] getArray() { return array; } /** * 這個方法十分重要 */ final void setArray(Object[] a) { array = a; } /** * 構造方法,使用空陣列初始化 */ public CopyOnWriteArrayList
() { setArray(new Object[0]); } /** * 使用 一個引數集合建立CopyOnwriteArrayList */ public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements,elements.length,Object[].class); } setArray(elements); } /** * 用陣列構造 */ public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn,toCopyIn.length,Object[].class)); } /** * 返回集合長度 */ public int size() { return getArray().length; } /** * 判斷集合是否為空 */ public boolean isEmpty() { return size() == 0; } /** * 判斷物件是否相等 */ private static boolean eq(Object o1,Object o2) { return (o1 == null) ? o2 == null : o1.equals(o2); } /** * 判斷一個一個物件在集合中的位置 */ private static int indexOf(Object o,Object[] elements,int index,int fence) { if (o == null) { for (int i = index; i < fence; i++) if (elements[i] == null) return i; } else { for (int i = index; i < fence; i++) if (o.equals(elements[i])) return i; } return -1; } /** * 返回指定物件在集合中的位置 */ private static int lastIndexOf(Object o,int index) { if (o == null) { for (int i = index; i >= 0; i--) if (elements[i] == null) return i; } else { for (int i = index; i >= 0; i--) if (o.equals(elements[i])) return i; } return -1; } /** * 判斷集合是否包含物件 */ public boolean contains(Object o) { Object[] elements = getArray(); return indexOf(o,elements,elements.length) >= 0; } /** * 返回物件在集合中的位置 */ public int indexOf(Object o) { Object[] elements = getArray(); return indexOf(o,elements.length); } /** * 返回物件在集合中的第一個位置,index代表從哪裡開始遍歷 */ public int indexOf(E e,int index) { Object[] elements = getArray(); return indexOf(e,index,elements.length); } /** * 返回物件在集合中的最後位置 */ public int lastIndexOf(Object o) { Object[] elements = getArray(); return lastIndexOf(o,elements.length - 1); } /** * 返回物件在集合中的最後位置,index代表從哪裡開始掃描 */ public int lastIndexOf(E e,int index) { Object[] elements = getArray(); return lastIndexOf(e,index); } /** * 返回一個集合的淺拷貝 */ public Object clone() { try { @SuppressWarnings("unchecked") CopyOnWriteArrayList<E> clone = (CopyOnWriteArrayList<E>) super.clone(); clone.resetLock(); return clone; } catch (CloneNotSupportedException e) { // this shouldn't happen,since we are Cloneable throw new InternalError(); } } /** * 返回集合中元素的陣列 */ public Object[] toArray() { Object[] elements = getArray(); return Arrays.copyOf(elements,elements.length); } /** * 返回指定型別的陣列 */ @SuppressWarnings("unchecked") public <T> T[] toArray(T a[]) { Object[] elements = getArray(); int len = elements.length; if (a.length < len) return (T[]) Arrays.copyOf(elements,len,a.getClass()); else { System.arraycopy(elements,a,len); if (a.length > len) a[len] = null; return a; } } @SuppressWarnings("unchecked") private E get(Object[] a,int index) { return (E) a[index]; } public E get(int index) { return get(getArray(),index); } /** * 將指定位置的元素設定成引數的元素 * 使用重入鎖,先複製一份元素陣列,然後拷貝,再將整個陣列替換 */ 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(); } } /** * 將指定元素拼接到list尾部 * 使用重入鎖對內部陣列進行拷貝,然後再替換整個陣列 */ 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(); } } /** * 將指定元素新增到指定的位置 * 分段複製 */ public void add(int index,E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+len); Object[] newElements; int numMoved = len - index; if (numMoved == 0) newElements = Arrays.copyOf(elements,len + 1); else { newElements = new Object[len + 1]; System.arraycopy(elements,newElements,index); System.arraycopy(elements,index + 1,numMoved); } newElements[index] = element; setArray(newElements); } 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)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements,numMoved); setArray(newElements); } return oldValue; } finally { lock.unlock(); } } /** * 刪除list中第一個相符的元素 */ public boolean remove(Object o) { Object[] snapshot = getArray(); int index = indexOf(o,snapshot,snapshot.length); return (index < 0) ? false : remove(o,index); } /** * 一樣 */ private boolean remove(Object o,Object[] snapshot,int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; if (snapshot != current) findIndex: { int prefix = Math.min(index,len); for (int i = 0; i < prefix; i++) { if (current[i] != snapshot[i] && eq(o,current[i])) { index = i; break findIndex; } } if (index >= len) return false; if (current[index] == o) break findIndex; index = indexOf(o,current,len); if (index < 0) return false; } Object[] newElements = new Object[len - 1]; System.arraycopy(current,index); System.arraycopy(current,len - index - 1); setArray(newElements); return true; } finally { lock.unlock(); } } /** * 刪除一段元素 */ void removeRange(int fromIndex,int toIndex) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (fromIndex < 0 || toIndex > len || toIndex < fromIndex) throw new IndexOutOfBoundsException(); int newlen = len - (toIndex - fromIndex); int numMoved = len - toIndex; if (numMoved == 0) setArray(Arrays.copyOf(elements,newlen)); else { Object[] newElements = new Object[newlen]; System.arraycopy(elements,fromIndex); System.arraycopy(elements,toIndex,fromIndex,numMoved); setArray(newElements); } } finally { lock.unlock(); } } /** * 如果list中無此元素,則新增 */ public boolean addIfAbsent(E e) { Object[] snapshot = getArray(); return indexOf(e,snapshot.length) >= 0 ? false : addIfAbsent(e,snapshot); } /** * 新增 */ private boolean addIfAbsent(E e,Object[] snapshot) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; if (snapshot != current) { // Optimize for lost race to another addXXX operation int common = Math.min(snapshot.length,len); for (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e,current[i])) return false; if (indexOf(e,common,len) >= 0) return false; } Object[] newElements = Arrays.copyOf(current,len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } } /** * 判斷list是否包含c的全部元素,注意這個方法是o(n2)的,能少用就少用 */ public boolean containsAll(Collection<?> c) { Object[] elements = getArray(); int len = elements.length; for (Object e : c) { if (indexOf(e,len) < 0) return false; } return true; } /** * 刪除全部元素,這個方法複雜度也很高,慎用 */ public boolean removeAll(Collection<?> c) { if (c == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len != 0) { // temp array holds those elements we know we want to keep int newlen = 0; Object[] temp = new Object[len]; for (int i = 0; i < len; ++i) { Object element = elements[i]; if (!c.contains(element)) temp[newlen++] = element; } if (newlen != len) { setArray(Arrays.copyOf(temp,newlen)); return true; } } return false; } finally { lock.unlock(); } } /** * 判斷list的元素是否全部包含列表c的元素,如果list中的某些元素不再c中,那麼這些元素將會被移除 * 如果list發生改變,就返回true */ public boolean retainAll(Collection<?> c) { if (c == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len != 0) { // temp array holds those elements we know we want to keep int newlen = 0; Object[] temp = new Object[len]; for (int i = 0; i < len; ++i) { Object element = elements[i]; if (c.contains(element)) temp[newlen++] = element; } if (newlen != len) { setArray(Arrays.copyOf(temp,newlen)); return true; } } return false; } finally { lock.unlock(); } } /** * 如果c的元素不存在list中,就在list尾部新增c中的元素 */ public int addAllAbsent(Collection<? extends E> c) { Object[] cs = c.toArray(); if (cs.length == 0) return 0; final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; int added = 0; // uniquify and compact elements in cs for (int i = 0; i < cs.length; ++i) { Object e = cs[i]; if (indexOf(e,len) < 0 && indexOf(e,cs,added) < 0) cs[added++] = e; } if (added > 0) { Object[] newElements = Arrays.copyOf(elements,len + added); System.arraycopy(cs,added); setArray(newElements); } return added; } finally { lock.unlock(); } } /** * 清空所有元素 */ public void clear() { final ReentrantLock lock = this.lock; lock.lock(); try { setArray(new Object[0]); } finally { lock.unlock(); } } /** * 將c中的所有元素都拼到list的尾部 */ public boolean addAll(Collection<? extends E> c) { Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ? ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray(); if (cs.length == 0) return false; final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len == 0 && cs.getClass() == Object[].class) setArray(cs); else { Object[] newElements = Arrays.copyOf(elements,len + cs.length); System.arraycopy(cs,cs.length); setArray(newElements); } return true; } finally { lock.unlock(); } } /** * 將c的元素新增到list的指定位置(index) */ public boolean addAll(int index,Collection<? extends E> c) { Object[] cs = c.toArray(); final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+len); if (cs.length == 0) return false; int numMoved = len - index; Object[] newElements; if (numMoved == 0) newElements = Arrays.copyOf(elements,len + cs.length); else { newElements = new Object[len + cs.length]; System.arraycopy(elements,index + cs.length,numMoved); } System.arraycopy(cs,cs.length); setArray(newElements); return true; } finally { lock.unlock(); } } /** * 迴圈遍歷 */ public void forEach(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); Object[] elements = getArray(); int len = elements.length; for (int i = 0; i < len; ++i) { @SuppressWarnings("unchecked") E e = (E) elements[i]; action.accept(e); } } /** * 刪除滿足filter條件的元素,如果list改變了就返回true,否則就返回false,說明沒有符合條件的元素 */ public boolean removeIf(Predicate<? super E> filter) { if (filter == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len != 0) { int newlen = 0; Object[] temp = new Object[len]; for (int i = 0; i < len; ++i) { @SuppressWarnings("unchecked") E e = (E) elements[i]; if (!filter.test(e)) temp[newlen++] = e; } if (newlen != len) { setArray(Arrays.copyOf(temp,newlen)); return true; } } return false; } finally { lock.unlock(); } } public void replaceAll(UnaryOperator<E> operator) { if (operator == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements,len); for (int i = 0; i < len; ++i) { @SuppressWarnings("unchecked") E e = (E) elements[i]; newElements[i] = operator.apply(e); } setArray(newElements); } finally { lock.unlock(); } } /** * 注意,排序也是有鎖的 */ public void sort(Comparator<? super E> c) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); Object[] newElements = Arrays.copyOf(elements,elements.length); @SuppressWarnings("unchecked") E[] es = (E[])newElements; Arrays.sort(es,c); setArray(newElements); } finally { lock.unlock(); } } /** * 將元素寫成位元組流 */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); Object[] elements = getArray(); // Write out array length s.writeInt(elements.length); // Write out all elements in the proper order. for (Object element : elements) s.writeObject(element); } /** * 讀取流,重新建立物件 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException,ClassNotFoundException { s.defaultReadObject(); // bind to new lock resetLock(); // Read in array length and allocate array int len = s.readInt(); SharedSecrets.getJavaOISAccess().checkArray(s,Object[].class,len); Object[] elements = new Object[len]; // Read in all elements in the proper order. for (int i = 0; i < len; i++) elements[i] = s.readObject(); setArray(elements); } /** * 就是陣列的toString */ public String toString() { return Arrays.toString(getArray()); } /** * 也就是說元素順序也要一致,才能判斷為相等 */ public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof List)) return false; List<?> list = (List<?>)(o); Iterator<?> it = list.iterator(); Object[] elements = getArray(); int len = elements.length; for (int i = 0; i < len; ++i) if (!it.hasNext() || !eq(elements[i],it.next())) return false; if (it.hasNext()) return false; return true; } /** * 返回這個列表的雜湊值 */ public int hashCode() { int hashCode = 1; Object[] elements = getArray(); int len = elements.length; for (int i = 0; i < len; ++i) { Object obj = elements[i]; hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode()); } return hashCode; } /** * 返回一個COW迭代器 */ public Iterator<E> iterator() { return new COWIterator<E>(getArray(),0); } /** * 返回一個COW迭代器 */ public ListIterator<E> listIterator() { return new COWIterator<E>(getArray(),0); } /** * 返回一個COW迭代器 */ public ListIterator<E> listIterator(int index) { Object[] elements = getArray(); int len = elements.length; if (index < 0 || index > len) throw new IndexOutOfBoundsException("Index: "+index); return new COWIterator<E>(elements,index); } /** * 返回一個Spliterator,這個具體是啥還沒研究 */ public Spliterator<E> spliterator() { return Spliterators.spliterator (getArray(),Spliterator.IMMUTABLE | Spliterator.ORDERED); } /** * COWIterator,增刪改操作全都是unsupported */ static final class COWIterator<E> implements ListIterator<E> { /** Snapshot of the array */ private final Object[] snapshot; /** Index of element to be returned by subsequent call to next. */ private int cursor; private COWIterator(Object[] elements,int initialCursor) { cursor = initialCursor; snapshot = elements; } public boolean hasNext() { return cursor < snapshot.length; } public boolean hasPrevious() { return cursor > 0; } @SuppressWarnings("unchecked") public E next() { if (! hasNext()) throw new NoSuchElementException(); return (E) snapshot[cursor++]; } @SuppressWarnings("unchecked") public E previous() { if (! hasPrevious()) throw new NoSuchElementException(); return (E) snapshot[--cursor]; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor-1; } public void remove() { throw new UnsupportedOperationException(); } public void set(E e) { throw new UnsupportedOperationException(); } public void add(E e) { throw new UnsupportedOperationException(); } @Override public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); Object[] elements = snapshot; final int size = elements.length; for (int i = cursor; i < size; i++) { @SuppressWarnings("unchecked") E e = (E) elements[i]; action.accept(e); } cursor = size; } } /** * 將指定位置的元素擷取成一個子列表,返回一個COWSubList */ public List<E> subList(int fromIndex,int toIndex) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (fromIndex < 0 || toIndex > len || fromIndex > toIndex) throw new IndexOutOfBoundsException(); return new COWSubList<E>(this,toIndex); } finally { lock.unlock(); } } /** * CopyOnWriteArrayList的子列表,初始化使用父列表的內部陣列,如果父列表的元素被修改 * 子列表的很多操作都會丟擲ConcurrentModificationException異常,具體可以看下checkForComodification * 所以subList方法其實是很有侷限性的,要考慮subList後list元素變化的情況。 */ private static class COWSubList<E> extends AbstractList<E> implements RandomAccess { private final CopyOnWriteArrayList<E> l; private final int offset; private int size; private Object[] expectedArray; // only call this holding l's lock COWSubList(CopyOnWriteArrayList<E> list,int fromIndex,int toIndex) { l = list; expectedArray = l.getArray(); offset = fromIndex; size = toIndex - fromIndex; } // only call this holding l's lock private void checkForComodification() { //元素不能修改,否則丟擲異常 if (l.getArray() != expectedArray) throw new ConcurrentModificationException(); } // only call this holding l's lock private void rangeCheck(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+size); } public E set(int index,E element) { final ReentrantLock lock = l.lock; lock.lock(); try { rangeCheck(index); checkForComodification(); E x = l.set(index+offset,element); expectedArray = l.getArray(); return x; } finally { lock.unlock(); } } public E get(int index) { final ReentrantLock lock = l.lock; lock.lock(); try { rangeCheck(index); checkForComodification(); return l.get(index+offset); } finally { lock.unlock(); } } public int size() { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); return size; } finally { lock.unlock(); } } public void add(int index,E element) { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); if (index < 0 || index > size) throw new IndexOutOfBoundsException(); l.add(index+offset,element); expectedArray = l.getArray(); size++; } finally { lock.unlock(); } } public void clear() { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); l.removeRange(offset,offset+size); expectedArray = l.getArray(); size = 0; } finally { lock.unlock(); } } public E remove(int index) { final ReentrantLock lock = l.lock; lock.lock(); try { rangeCheck(index); checkForComodification(); E result = l.remove(index+offset); expectedArray = l.getArray(); size--; return result; } finally { lock.unlock(); } } public boolean remove(Object o) { int index = indexOf(o); if (index == -1) return false; remove(index); return true; } public Iterator<E> iterator() { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); return new COWSubListIterator<E>(l,offset,size); } finally { lock.unlock(); } } public ListIterator<E> listIterator(int index) { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+size); return new COWSubListIterator<E>(l,size); } finally { lock.unlock(); } } public List<E> subList(int fromIndex,int toIndex) { final ReentrantLock lock = l.lock; lock.lock(); try { checkForComodification(); if (fromIndex < 0 || toIndex > size || fromIndex > toIndex) throw new IndexOutOfBoundsException(); return new COWSubList<E>(l,fromIndex + offset,toIndex + offset); } finally { lock.unlock(); } } public void forEach(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); int lo = offset; int hi = offset + size; Object[] a = expectedArray; if (l.getArray() != a) throw new ConcurrentModificationException(); if (lo < 0 || hi > a.length) throw new IndexOutOfBoundsException(); for (int i = lo; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) a[i]; action.accept(e); } } public void replaceAll(UnaryOperator<E> operator) { if (operator == null) throw new NullPointerException(); final ReentrantLock lock = l.lock; lock.lock(); try { int lo = offset; int hi = offset + size; Object[] elements = expectedArray; if (l.getArray() != elements) throw new ConcurrentModificationException(); int len = elements.length; if (lo < 0 || hi > len) throw new IndexOutOfBoundsException(); Object[] newElements = Arrays.copyOf(elements,len); for (int i = lo; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) elements[i]; newElements[i] = operator.apply(e); } l.setArray(expectedArray = newElements); } finally { lock.unlock(); } } public void sort(Comparator<? super E> c) { final ReentrantLock lock = l.lock; lock.lock(); try { int lo = offset; int hi = offset + size; Object[] elements = expectedArray; if (l.getArray() != elements) throw new ConcurrentModificationException(); int len = elements.length; if (lo < 0 || hi > len) throw new IndexOutOfBoundsException(); Object[] newElements = Arrays.copyOf(elements,len); @SuppressWarnings("unchecked") E[] es = (E[])newElements; Arrays.sort(es,lo,hi,c); l.setArray(expectedArray = newElements); } finally { lock.unlock(); } } public boolean removeAll(Collection<?> c) { if (c == null) throw new NullPointerException(); boolean removed = false; final ReentrantLock lock = l.lock; lock.lock(); try { int n = size; if (n > 0) { int lo = offset; int hi = offset + n; Object[] elements = expectedArray; if (l.getArray() != elements) throw new ConcurrentModificationException(); int len = elements.length; if (lo < 0 || hi > len) throw new IndexOutOfBoundsException(); int newSize = 0; Object[] temp = new Object[n]; for (int i = lo; i < hi; ++i) { Object element = elements[i]; if (!c.contains(element)) temp[newSize++] = element; } if (newSize != n) { Object[] newElements = new Object[len - n + newSize]; System.arraycopy(elements,lo); System.arraycopy(temp,newSize); System.arraycopy(elements,lo + newSize,len - hi); size = newSize; removed = true; l.setArray(expectedArray = newElements); } } } finally { lock.unlock(); } return removed; } public boolean retainAll(Collection<?> c) { if (c == null) throw new NullPointerException(); boolean removed = false; final ReentrantLock lock = l.lock; lock.lock(); try { int n = size; if (n > 0) { int lo = offset; int hi = offset + n; Object[] elements = expectedArray; if (l.getArray() != elements) throw new ConcurrentModificationException(); int len = elements.length; if (lo < 0 || hi > len) throw new IndexOutOfBoundsException(); int newSize = 0; Object[] temp = new Object[n]; for (int i = lo; i < hi; ++i) { Object element = elements[i]; if (c.contains(element)) temp[newSize++] = element; } if (newSize != n) { Object[] newElements = new Object[len - n + newSize]; System.arraycopy(elements,len - hi); size = newSize; removed = true; l.setArray(expectedArray = newElements); } } } finally { lock.unlock(); } return removed; } public boolean removeIf(Predicate<? super E> filter) { if (filter == null) throw new NullPointerException(); boolean removed = false; final ReentrantLock lock = l.lock; lock.lock(); try { int n = size; if (n > 0) { int lo = offset; int hi = offset + n; Object[] elements = expectedArray; if (l.getArray() != elements) throw new ConcurrentModificationException(); int len = elements.length; if (lo < 0 || hi > len) throw new IndexOutOfBoundsException(); int newSize = 0; Object[] temp = new Object[n]; for (int i = lo; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) elements[i]; if (!filter.test(e)) temp[newSize++] = e; } if (newSize != n) { Object[] newElements = new Object[len - n + newSize]; System.arraycopy(elements,len - hi); size = newSize; removed = true; l.setArray(expectedArray = newElements); } } } finally { lock.unlock(); } return removed; } public Spliterator<E> spliterator() { int lo = offset; int hi = offset + size; Object[] a = expectedArray; if (l.getArray() != a) throw new ConcurrentModificationException(); if (lo < 0 || hi > a.length) throw new IndexOutOfBoundsException(); return Spliterators.spliterator (a,Spliterator.IMMUTABLE | Spliterator.ORDERED); } } private static class COWSubListIterator<E> implements ListIterator<E> { private final ListIterator<E> it; private final int offset; private final int size; COWSubListIterator(List<E> l,int offset,int size) { this.offset = offset; this.size = size; it = l.listIterator(index+offset); } public boolean hasNext() { return nextIndex() < size; } public E next() { if (hasNext()) return it.next(); else throw new NoSuchElementException(); } public boolean hasPrevious() { return previousIndex() >= 0; } public E previous() { if (hasPrevious()) return it.previous(); else throw new NoSuchElementException(); } public int nextIndex() { return it.nextIndex() - offset; } public int previousIndex() { return it.previousIndex() - offset; } public void remove() { throw new UnsupportedOperationException(); } public void set(E e) { throw new UnsupportedOperationException(); } public void add(E e) { throw new UnsupportedOperationException(); } @Override public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); int s = size; ListIterator<E> i = it; while (nextIndex() < s) { action.accept(i.next()); } } } // Support for resetting lock while deserializing private void resetLock() { UNSAFE.putObjectVolatile(this,lockOffset,new ReentrantLock()); } private static final sun.misc.Unsafe UNSAFE; private static final long lockOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> k = CopyOnWriteArrayList.class; lockOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("lock")); } catch (Exception e) { throw new Error(e); } } } 複製程式碼

擴充套件閱讀

待施工

  • Spliterators

總結

看了CopyOnWriteArrayList原始碼,其原理很好理解,它的修改操作使用ReentrantLock進行同步,建立一個內部元素陣列的複製,在修改操作結束後 替換原有的陣列,CopyOnWriteArrayList的遍歷使用內部元素陣列的快照來建立一個COWIterator,其實遍歷的是這個快照的元素,此時如果CopyOnWriteArrayList 的內部元素有修改,快照的元素是不影響的,因為那些修改的方法直接將CopyOnWriteArrayList的內部陣列的引用設定到新的陣列上,而遍歷者還在引用原來的陣列。 也就是說併發讀和修改時,記憶體中會有兩個版本的陣列,一個是老版本,這個老版本被各個遍歷者引用,一個是新版本,CopyOnWriteArrayList內部陣列會在修改完畢後引用新版本, 所以多執行緒遍歷和修改時不會丟擲ConcurrentModificationException。而且它的迭代器是不支援修改操作的,只能進行讀 操作,所以快照版本的陣列只要建立後就不會變了。還要注意使用CopyOnWriteArrayList建立subList功能也是受限的,因為如果對subList做操作時會 校驗父列表的元素是否已經修改,如果修改操作是會丟擲異常的,需要想清楚再使用。 綜合以上特點,可以發現CopyOnWriteArrayList不適合那些頻繁寫操作的場景,而且元素數量也不宜太多,否則陣列拷貝的記憶體開銷太大。 一個比較常用的場景是觀察者模式中,觀察者遍歷監聽者列表,這個監聽者列表可以使用CopyOnWriteArrayList來儲存,因為監聽者數量一般最多也就幾百 幾千,如果出現監聽者退出監聽,也不會影響觀察者遍歷列表。