(轉)線程安全的CopyOnWriteArrayList介紹

轉載自:線程安全的CopyOnWriteArrayList介紹


證明CopyOnWriteArrayList是線程安全的

先寫一段代碼證明CopyOnWriteArrayList確實是線程安全的。


讀線程


寫線程


測試代碼

運行上面的代碼,沒有報出

java.util.ConcurrentModificationException

1

說明了CopyOnWriteArrayList并發(fā)多線程的環(huán)境下,仍然能很好的工作。

CopyOnWriteArrayList如何做到線程安全的

CopyOnWriteArrayList使用了一種叫寫時復制的方法,當有新元素添加到CopyOnWriteArrayList時,先從原有的數組中拷貝一份出來,然后在新的數組做寫操作,寫完之后,再將原來的數組引用指向到新數組。

當有新元素加入的時候,如下圖,創(chuàng)建新數組,并往新數組中加入一個新元素,這個時候,array這個引用仍然是指向原數組的。

當元素在新數組添加成功后,將array這個引用指向新數組。

CopyOnWriteArrayList的整個add操作都是在的保護下進行的。?

這樣做是為了避免在多線程并發(fā)add的時候,復制出多個副本出來,把數據搞亂了,導致最終的數組數據不是我們期望的。

CopyOnWriteArrayList的add操作的源代碼如下:

publicbooleanadd(E e) {//1、先加鎖final ReentrantLocklock=this.lock;lock.lock();try{? ? ? ? Object[] elements = getArray();intlen = elements.length;//2、拷貝數組Object[] newElements = Arrays.copyOf(elements, len +1);//3、將元素加入到新數組中newElements[len] = e;//4、將array引用指向到新數組setArray(newElements);returntrue;? ? }finally{//5、解鎖lock.unlock();? ? }}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

由于所有的寫操作都是在新數組進行的,這個時候如果有線程并發(fā)的寫,則通過鎖來控制,如果有線程并發(fā)的讀,則分幾種情況:?

1、如果寫操作未完成,那么直接讀取原數組的數據;?

2、如果寫操作完成,但是引用還未指向新數組,那么也是讀取原數組數據;?

3、如果寫操作完成,并且引用已經指向了新的數組,那么直接從新數組中讀取數據。

可見,CopyOnWriteArrayList的讀操作是可以不用加鎖的。

CopyOnWriteArrayList的使用場景

通過上面的分析,CopyOnWriteArrayList?有幾個缺點:?

1、由于寫操作的時候,需要拷貝數組,會消耗內存,如果原數組的內容比較多的情況下,可能導致young gc或者full gc

2、不能用于實時讀的場景,像拷貝數組、新增元素都需要時間,所以調用一個set操作后,讀取到數據可能還是舊的,雖然CopyOnWriteArrayList?能做到最終一致性,但是還是沒法滿足實時性要求;

CopyOnWriteArrayList?合適讀多寫少的場景,不過這類慎用?

因為誰也沒法保證CopyOnWriteArrayList?到底要放置多少數據,萬一數據稍微有點多,每次add/set都要重新復制數組,這個代價實在太高昂了。在高性能的互聯(lián)網應用中,這種操作分分鐘引起故障。

CopyOnWriteArrayList透露的思想

如上面的分析CopyOnWriteArrayList表達的一些思想:?

1、讀寫分離,讀和寫分開?

2、最終一致性?

3、使用另外開辟空間的思路,來解決并發(fā)沖突

參考的文章

JAVA中的COPYONWRITE容器

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容