JAVA并發(fā)梳理(六)CopyOnWriteArrayList

Copy-On-Write簡稱COW,是一種用于程序設(shè)計中的優(yōu)化策略。其基本思路是,從一開始大家都在共享同一個內(nèi)容,當某個人想要修改這個內(nèi)容的時候,才會真正把內(nèi)容Copy出去形成一個新的內(nèi)容然后再改,這是一種延時懶惰策略。從JDK1.5開始Java并發(fā)包里提供了兩個使用CopyOnWrite機制實現(xiàn)的并發(fā)容器,它們是CopyOnWriteArrayListCopyOnWriteArraySet。

本節(jié)重點梳理下CopyOnWriteArrayList。

CopyOnWriteArrayList是線程安全的

在多個線程對同一個CopyOnWriteArrayList讀和寫的情況下,它不會拋出java.util.ConcurrentModificationException

CopyOnWriteArrayList是怎么保證線程安全的呢?

CopyOnWriteArrayList使用了一種叫寫時復(fù)制的方法,當有新元素添加到CopyOnWriteArrayList時,先從原有的數(shù)組中拷貝一份出來,然后在新的數(shù)組做寫操作,寫完之后,再將原來的數(shù)組引用指向到新數(shù)組。
CopyOnWriteArrayList的整個add操作都是在鎖的保護下進行的。
這樣做是為了避免在多線程并發(fā)add的時候,復(fù)制出多個副本出來,把數(shù)據(jù)搞亂了,導(dǎo)致最終的數(shù)組數(shù)據(jù)不是我們期望的。以下是add源碼:

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();
        }
    }

由于所有的寫操作都是在新數(shù)組進行的,這個時候如果有線程并發(fā)的寫,則通過鎖來控制,如果有線程并發(fā)的讀,則分幾種情況:
1、如果寫操作未完成,那么直接讀取原數(shù)組的數(shù)據(jù);
2、如果寫操作完成,但是引用還未指向新數(shù)組,那么也是讀取原數(shù)組數(shù)據(jù);
3、如果寫操作完成,并且引用已經(jīng)指向了新的數(shù)組,那么直接從新數(shù)組中讀取數(shù)據(jù)。
可見,CopyOnWriteArrayList的讀操作是可以不用加鎖的。

CopyOnWriteArrayList的使用場景

通過上面的分析,CopyOnWriteArrayList有幾個缺點:
1、由于寫操作的時候,需要拷貝數(shù)組,會消耗內(nèi)存,如果原數(shù)組的內(nèi)容比較多的情況下,可能導(dǎo)致young gc或者full gc。
2、不能用于實時讀的場景,像拷貝數(shù)組、新增元素都需要時間,所以調(diào)用一個set操作后,讀取到數(shù)據(jù)可能還是舊的,雖然CopyOnWriteArrayList 能做到最終一致性,但是還是沒法滿足實時性要求;

CopyOnWriteArrayList 合適讀多寫少的場景,不過這類慎用
因為誰也沒法保證CopyOnWriteArrayList 到底要放置多少數(shù)據(jù),萬一數(shù)據(jù)稍微有點多,每次add/set都要重新復(fù)制數(shù)組,這個代價實在太高昂了。在高性能的互聯(lián)網(wǎng)應(yīng)用中,這種操作分分鐘引起故障。

CopyOnWriteArrayList透露的思想

如上面的分析CopyOnWriteArrayList表達的一些思想:
1、讀寫分離,讀和寫分開,減少讀和寫的并發(fā)沖突
2、最終一致性
3、使用另外開辟空間的思路,來解決并發(fā)沖突

使用注意

使用批量添加。因為每次添加,容器每次都會進行復(fù)制,所以減少添加次數(shù),可以減少容器的復(fù)制次數(shù)。

引用
線程安全的CopyOnWriteArrayList介紹
聊聊并發(fā)-Java中的Copy-On-Write容器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容