前言
ArrayList的線程安全的版本,由名稱可以看出這個集合的特點就是:在寫時復制數(shù)組,讀無鎖的的ArrayList。 元素可以為null
定義
實現(xiàn)了List、RandomAccess、Cloneable、java.io.Serializable接口
重要的字段
使用ReentrantLock來保證線程安全,而不是synchronized同步方法;
array緩存數(shù)組只可以通過getArray(),setArray(Object[] a)來訪問,而且是volatile修飾的,保證線程可見性,與ArrayList不同。
構造器
無參構造方法,需要注意的是,ArrayList的無參構造器內(nèi)是將一個空數(shù)組賦給緩沖數(shù)組,使用的是延遲初始化,只有在第一次調(diào)用add方法時才會去創(chuàng)建一個默認長度為10的數(shù)組,并把引用賦給緩沖數(shù)組;而CopyOnWriteArrayList是直接在構造器內(nèi)創(chuàng)建一個長度為0的Object對象數(shù)組,并沒有采取延遲初始化。
集合構造器
外部緩存數(shù)組構造器,將構造器內(nèi)的參數(shù)數(shù)組作為CopyOnWriteArrayList內(nèi)部的緩沖數(shù)組
add方法
add到尾部
可見在每一次add方法都將復制一遍數(shù)組,并創(chuàng)建一個長度+1的新數(shù)組,然后將新添加的元素放入到數(shù)組的最后,然后更新緩存數(shù)組的引用。
add到指定位置(隨機訪問API)
當添加的位置在數(shù)組的尾部在只需復制一次數(shù)組,當位于中間位置則需要復制兩次。
remove方法
刪除第一個與指定元素相等的集合內(nèi)元素,我們發(fā)現(xiàn)對remove方法的優(yōu)化,即利用array數(shù)組的線程可見性,無鎖獲取一個快照,如果在這個快照中沒有指定元素則返回false,如果含有指定元素,需要調(diào)用remove(Object o, Object[] snapshot, int index)方法加鎖進行遍歷并刪除。即避免了在不含有指定元素的情況下加鎖遍歷的過程。
需要注意indexOf方法是通過equal方法比較是否存在的。
私有方法
刪除指定位置上的元素
當刪除的元素在數(shù)組的末尾則只進行一次數(shù)組復制,當個刪除的元素位于中間則需要復制兩次數(shù)組,最后更新數(shù)組應用。
get方法
無鎖獲取元素,性能較高;但是array的元素的變化還沒有刷新到主內(nèi)存上(set方法,通過鎖來保證元素的可見性)、或者復制數(shù)組的過程中,還沒有更新數(shù)組引用(add方法);即鎖還沒有釋放,這時另外一個線程去讀,所以會出現(xiàn)臟讀。
注意:volatile數(shù)組的可見性問題
volatile的數(shù)組只針對數(shù)組的引用具有volatile的語義,而不是它的元素
size和isEmpty方法
同樣會出現(xiàn)臟讀,比如add方法在復制數(shù)組的過程中,此時調(diào)用size、isEmpty方法
iterator迭代器方法
iterator 和 listIterator 的弱一致性
COWIterator不支持的方法
下面分析中iterator和listIterator都記為iterator
- 調(diào)用iterator方法后會創(chuàng)建一個新的COWIterator對象實例(實現(xiàn)了ListIterator接口),并保存了一個當前數(shù)組的快照,在調(diào)用next遍歷時則僅僅對此快照數(shù)組進行遍歷,因此 CopyOnWriteArrayList不會拋出ConcurrentModificatiedException異常,但是會出現(xiàn)臟讀問題。
- 由于是對快照進行操作所以迭代器方法僅支持讀操作,不支持和寫操作相關的任何操作(如 remove,set,add),調(diào)用將拋出NoSuchElementException異常。
其他方法列表
總結
CopyOnWriteArrayList 基于ReentranLock保證了增加元素和刪除元素動作的互斥。每一次寫操作(remove,add等相關的)都將會創(chuàng)建數(shù)組復制元素,這將造成頻繁寫極大的性能消耗。在讀操作上沒有加鎖,保證了讀的性能,但是卻會出現(xiàn)臟讀的問題(get、iterator、size、isEmpty)。綜上CopyOnWriteArrayList 適合讀多寫少,對實時性不敏感的應用場景。
允許null元素
參考鏈接
http://ifeve.com/java-copy-on-write/
http://caoyaojun1988-163-com.iteye.com/blog/1754686
















