一、背景java
java誕生之初 就有線程安全的Vector,但Vector對讀寫都是經過synchronized關鍵字來同步的,性能並很差數組
且Vector每次擴容是原來的1倍,存在內存浪費的可能。安全
對於線程安全的List JDK提供了CopyOnWriteArrayList多線程
二、原理app
2.1 CopyOnWriteArrayList 使用寫時複製技術,讀寫分離ide
對於寫操做,會使用ReentrantLock加鎖,對底層數組拷貝一份,進行修改,修改完後再覆蓋原來的數組性能
2.2 底層使用數組this
private transient volatile Object[] array;spa
數據使用volatile修飾,故能保證可見性,存在happens-before關係,使得能讀到最新的數據線程
2.3 使用ReentrantLock修改
全部的寫操做 讀會加鎖保證線程安全
但讀操做是沒有任何鎖的,故修改過程當中的數據,此時另外一個線程是讀不到的。
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 迭代時安全失敗的,不容許在迭代過程當中刪除元素,以下會拋出異常
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
/** * Not supported. Always throws UnsupportedOperationException. * @throws UnsupportedOperationException always; {@code remove} * is not supported by this iterator. */ public void remove() { throw new UnsupportedOperationException(); } /** * Not supported. Always throws UnsupportedOperationException. * @throws UnsupportedOperationException always; {@code set} * is not supported by this iterator. */ public void set(E e) { throw new UnsupportedOperationException(); } /** * Not supported. Always throws UnsupportedOperationException. * @throws UnsupportedOperationException always; {@code add} * is not supported by this iterator. */ public void add(E e) { throw new UnsupportedOperationException(); }
建立迭代時,引用了原數組,故迭代過程當中如何修改了CopyOnWriteArrayList,
迭代也不會感知。仍是對修改前的數據進行訪問(注意這是針對數據元素的增刪而言,如何存放對象,對象內部的變化仍是有影響的)
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; }
四、使用場景
缺點:
a. 每次修改都會拷貝數組 佔用內存 寫性能不高
b.修改的過程當中 數據依賴讀的是老的數據 ,只能保證最終一致 不能保證強一致性
使用場景
一、多線程 讀多寫少。
二、不要求數據強一致性。
不然推薦使用Collections.synchronziedList