- CopyOnWriteArrayList,寫數(shù)組的拷貝回懦,支持高效率并發(fā)且是線程安全的,讀操作無鎖的ArrayList气笙。所有可變操作都是通過對底層數(shù)組進(jìn)行一次新的復(fù)制來實(shí)現(xiàn)。
- CopyOnWriteArrayList適合使用在讀操作遠(yuǎn)遠(yuǎn)大于寫操作的場景里怯晕,比如緩存潜圃。它不存在擴(kuò)容的概念,每次寫操作都要復(fù)制一個副本舟茶,在副本的基礎(chǔ)上修改后改變Array引用谭期。CopyOnWriteArrayList中寫操作需要大面積復(fù)制數(shù)組,所以性能肯定很差
- 在迭代器上進(jìn)行的元素更改操作(remove吧凉、set和add)不受支持隧出。這些方法將拋出UnsupportedOperationException。
定義
CopyOnWriteArrayList跟ArrayList一樣實(shí)現(xiàn)了List<E>, RandomAccess, Cloneable, Serializable接口客燕,但是沒有繼承AbstractList鸳劳。
初始化時(shí)候新建一個容量為0的數(shù)組余素。
add(E e)方法
public boolean add(E e) {
//獲得鎖垦写,添加的時(shí)候首先進(jìn)行鎖定
final ReentrantLock lock = this.lock;
lock.lock();
try {
//獲取當(dāng)前數(shù)組
Object[] elements = getArray();
//獲取當(dāng)前數(shù)組的長度
int len = elements.length;
//這個是重點(diǎn)谢翎,創(chuàng)建新數(shù)組赤屋,容量為舊數(shù)組長度加1伶授,將舊數(shù)組拷貝到新數(shù)組中
Object[] newElements = Arrays.copyOf(elements, len + 1);
//要添加的數(shù)據(jù)添加到新數(shù)組的末尾
newElements[len] = e;
//將數(shù)組引用指向新數(shù)組涮因,完成了添加元素操作
setArray(newElements);
return true;
} finally {
//解鎖
lock.unlock();
}
}
從上面來說拒迅,每次添加一個新元素都會長度加1沥寥,然后復(fù)制整個舊數(shù)組颤练,由此可見對于寫多的操作既忆,效率肯定不會很好。所以CopyOnWriteArrayList適合讀多寫少的場景。
add(int index, E element)方法
public void add(int index, E element) {
//同樣也是先加鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
//獲取舊數(shù)組
Object[] elements = getArray();
//獲取舊數(shù)組長度
int len = elements.length;
//校驗(yàn)指定的index
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)//需要插入的位置正好等于數(shù)組長度患雇,數(shù)組長度加1跃脊,舊數(shù)據(jù)拷貝到新數(shù)組
newElements = Arrays.copyOf(elements, len + 1);
else {
//新數(shù)組長度增加1
newElements = new Object[len + 1];
//分兩次拷貝,第一次拷貝舊數(shù)組0到index處的到新數(shù)組0到index苛吱,第二次拷貝舊數(shù)組index到最后的數(shù)組到新數(shù)組index+1到最后
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
//index初插入數(shù)據(jù)
newElements[index] = element;
//新數(shù)組指向全局?jǐn)?shù)組
setArray(newElements);
} finally {
//解鎖
lock.unlock();
}
}
set(int index, E element)方法
public E set(int index, E element) {
//修改元素之前首先加鎖
final ReentrantLock lock = this.lock;
lock.lock();
try {
//獲取原來的數(shù)組
Object[] elements = getArray();
//index位置的元素
E oldValue = get(elements, index);
//新舊值不相等才進(jìn)行替換
if (oldValue != element) {
//原來的長度
int len = elements.length;
//拷貝一份到新數(shù)組
Object[] newElements = Arrays.copyOf(elements, len);
//替換元素
newElements[index] = element;
//新數(shù)組指向全局?jǐn)?shù)組
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
//解鎖
lock.unlock();
}
}
get(int index)方法
讀的時(shí)候不加鎖酪术,代碼如下:
public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}
remove()
remove方法不再過多介紹,看完add和set方法應(yīng)該就能理解翠储。
迭代
內(nèi)部類COWIterator 實(shí)現(xiàn)了ListIterator接口绘雁。迭代的時(shí)候不能進(jìn)行remove,add援所,set等方法庐舟,會拋異常。
迭代速度快住拭,迭代時(shí)是迭代的數(shù)組快照挪略。
/** Snapshot of the array */
private final Object[] snapshot;
源碼分析
jdk1.7.0_71
//鎖,保護(hù)所有存取器
transient final ReentrantLock lock = new ReentrantLock();
//保存數(shù)據(jù)的數(shù)組
private volatile transient Object[] array;
final Object[] getArray() {return array;}
final void setArray(Object[] a) {array = a;}
空構(gòu)造,初始化一個長度為0的數(shù)組
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
利用集合初始化一個CopyOnWriteArrayList
public CopyOnWriteArrayList(Collection<? extends E> c) {}
利用數(shù)組初始化一個CopyOnWriteArrayList
public CopyOnWriteArrayList(E[] toCopyIn) {}
size() 大小
public int size() {}
isEmpty()是否為空
public boolean isEmpty(){}
indexOf(Object o, Object[] elements,int index, int fence) 元素索引
private static int indexOf(Object o, Object[] elements,int index, int fence) {}
indexOf() 元素索引
public int indexOf(Object o){}
indexOf(E e, int index) 元素索引
public int indexOf(E e, int index) {}
lastIndexOf(Object o, Object[] elements, int index) 元素索引,最后一個
private static int lastIndexOf(Object o, Object[] elements, int index) {}
lastIndexOf(Object o) 元素索引,最后一個
public int indexOf(E e, int index) {}
lastIndexOf(E e, int index) 元素索引,最后一個
public int lastIndexOf(E e, int index) {}
contains(Object o) 是否包含元素
public boolean contains(Object o){}
clone() 淺拷貝
public Object clone() {}
toArray() 轉(zhuǎn)換成數(shù)組
public Object[] toArray(){}
toArray(T a[]) 轉(zhuǎn)換成指定類型的數(shù)組
public <T> T[] toArray(T a[]) {}
E get(int index)獲取指定位置的元素
public E get(int index){}
set(int index, E element) 指定位置設(shè)置元素
寫元素的時(shí)候,先獲得鎖,finall塊中釋放鎖
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();
}
}
add(E e) 元素添加到末尾
public boolean add(E e) {}
add(int index, E element) 指定位置之后插入元素
public void add(int index, E element){}
remove(int index)刪除指定位置的元素
public E remove(int index) {}
remove(Object o) 刪除第一個匹配的元素
public boolean remove(Object o) {}
removeRange(int fromIndex, int toIndex) 刪除指定區(qū)間的元素
private void removeRange(int fromIndex, int toIndex) {}
addIfAbsent(E e) 如果元素不存在就添加進(jìn)list中
public boolean addIfAbsent(E e){}
containsAll(Collection<?> c)是否包含全部
public boolean containsAll(Collection<?> c){}
removeAll(Collection<?> c) 移除全部包含在集合中的元素
public boolean removeAll(Collection<?> c){}
retainAll(Collection<?> c) 保留指定集合的元素,其他的刪除
public boolean retainAll(Collection<?> c){}
addAllAbsent(Collection<? extends E> c) 如果不存在就添加進(jìn)去
public int addAllAbsent(Collection<? extends E> c) {}
clear() 清空list
public void clear(){}
addAll(Collection<? extends E> c)添加集合中的元素到尾部
public void addAll(Collection<? extends E> c){}
addAll(int index, Collection<? extends E> c) 添加集合中元素到指定位置之后
public boolean addAll(int index, Collection<? extends E> c){}
toString()
public String toString(){}
equals(Object o)
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;
}
hashCode()
public int hashCode{}
listIterator(final int index)和 listIterator() 返回一個迭代器,支持向前和向后遍歷
public ListIterator<E> listIterator(final int index) {}
public ListIterator<E> listIterator() {}
iterator() 只能向后遍歷
public Iterator<E> iterator() {}
subList() 返回部分list
public List<E> subList(int fromIndex, int toIndex) {
...
return new COWSubList<E>(this, fromIndex, toIndex);
...
}
參考
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845656.html