When
CopyOnWriteArrayList 是jdk1.5以后并發(fā)包中提供的一種并發(fā)容器工禾,寫操作通過(guò)創(chuàng)建底層數(shù)組的新副本來(lái)實(shí)現(xiàn),是一種讀寫分離的并發(fā)策略帽揪,我們也成為“寫時(shí)復(fù)制容器”,類似的容器還有 CopyOnWriteArraySet。
Why
眾所周知疾掰,集合框架中的ArrayList 是非線程安全的,Vector雖然是線程安全的徐紧,但是處理方式簡(jiǎn)單粗暴(synchronized),性能較差静檬。而CopyOnWriteArrayList提供了不同的處理并發(fā)的思路。
How
很多時(shí)候并级,我們系統(tǒng)中處理的都是讀多寫少的并發(fā)場(chǎng)景拂檩。CopyOnWriterArrayList 允許并發(fā)的讀,讀操作是無(wú)鎖的嘲碧,性能較高稻励。寫操作的話,比如向容器增加一個(gè)元素愈涩,則首先將當(dāng)前容器復(fù)制一份望抽,然后在新副本上執(zhí)行寫操作,結(jié)束之后再將原容器的引用指向新容器钠署。
優(yōu)缺點(diǎn)分析
了解了CopyOnWriteArrayList原理糠聪,接下來(lái)分析優(yōu)缺點(diǎn)及使用場(chǎng)景
優(yōu)點(diǎn):
讀操作性能很高,因?yàn)闊o(wú)需任何同步措施谐鼎,比較適用于讀多寫少的并發(fā)場(chǎng)景舰蟆。Java 的 list 在遍歷時(shí),若中途有其他線程對(duì)容器進(jìn)行修改狸棍,則會(huì)拋出ConcurrentModificationException 異常身害。而CopyOnWriteArrayList由于其“讀寫分離”的思想,遍歷和修改操作分別作用在不同的 list容器草戈,所以迭代的時(shí)候不會(huì)拋出 ConcurrentModificationExecption 異常了塌鸯。
缺點(diǎn):
缺點(diǎn)也很明顯,一是內(nèi)存占用問(wèn)題唐片,畢竟每次執(zhí)行寫操作都要將原容器拷貝一份丙猬,數(shù)據(jù)量大時(shí)涨颜,對(duì)內(nèi)存壓力較大,甚至可能引起頻繁GC茧球,二是無(wú)法保證實(shí)時(shí)性庭瑰,Vector 對(duì)讀寫操作均加鎖同步,可以保證容器的讀寫強(qiáng)一致性抢埋,CopyOnWriteArrayList由于其實(shí)現(xiàn)策略的原因弹灭,寫和讀分別作用于不容容器上,在寫的過(guò)程中揪垄,讀是不會(huì)發(fā)生阻塞的穷吮,未切換索引置新容器時(shí),是讀不到剛寫入的數(shù)據(jù)的饥努。
源碼分析
原理理解了捡鱼,再來(lái)分析源碼吧~~~~~
public boolean add(E e) { //加鎖,對(duì)寫操作保證線程安全 final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; //拷貝原容器酷愧,長(zhǎng)度為原容器+1 Object[] newElements = Arrays.copyOf(elements, len + 1); //在新副本執(zhí)行添加操作 newElements[len] = e; //底層數(shù)組指向新的數(shù)組 setArray(newElements); return true; } finally { lock.unlock(); } } 其中 底層數(shù)組定義如下: private transient volatile Object[] array; 增加內(nèi)存可見(jiàn)性堰汉。
同理可以分析刪除操作。
總結(jié)
其實(shí)并發(fā)容器的優(yōu)缺點(diǎn)伟墙,是要根據(jù)我們實(shí)際的業(yè)務(wù)場(chǎng)景做出取舍的。
但前提是滴铅,你要了解他們各自的優(yōu)缺點(diǎn)戳葵,謝謝!