CopyOnWriteArrayList

CopyOnWriteArrayList

四個關注點

關 注 點 結 論
CopyOnWriteArrayList是否容許空 容許
CopyOnWriteArrayList是否容許重複數據 容許
CopyOnWriteArrayList是否有序 有序
CopyOnWriteArrayList是否線程安全 線程安全

首先提兩點:java

一、CopyOnWriteArrayList位於java.util.concurrent包下,可想而知,這個類是爲併發而設計的數據庫

二、CopyOnWriteArrayList,顧名思義,Write的時候老是要Copy,也就是說對於CopyOnWriteArrayList,任何可變的操做(add、set、remove等等)都是伴隨複製這個動做的,後面會解讀CopyOnWriteArrayList的底層實現機制數組

對於CopyOnWriteArrayList來講,增長、刪除、修改、插入的原理都是同樣的,話很少說,用源碼和圖進行演示:緩存

1 public static void main(String[] args)
2 {
3     List<Integer> list = new CopyOnWriteArrayList<Integer>();
4     list.add(1);
5     list.add(2);
6 }

源碼安全

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

每一步都清楚地表示在圖上了,一次add大體經歷了幾個步驟:併發

一、加鎖分佈式

二、拿到原數組,獲得新數組的大小(原數組大小+1),實例化出一個新的數組來高併發

三、把原數組的元素複製到新數組中去this

四、新數組最後一個位置設置爲待添加的元素(由於新數組的大小是按照原數組大小+1來的)atom

五、把Object array引用指向新數組

六、解鎖

整個過程看起來比較像ArrayList的擴容。有了這個基礎,咱們再來看一下第5行的add了一個整數2作了什麼,這應該很是簡單了,仍是畫一張圖來表示:

另外,插入、刪除、修改操做也都是同樣,每一次的操做都是以對Object[] array進行一次複製爲基礎的,若是上面的流程看懂了,那麼研究插入、刪除、修改的源代碼應該不難。

爲何要用CopyOnWriteArrayList而不用其餘的?

這個就和 原子性一致性 有關,ArrayList 和 linkedList 首先線程不安全就不知足,還有一種vector ,雖說線程是安全的,可是不是絕對的安全,只是在單獨的增、刪、改時能夠,可是在組合的時候就不行,因此這裏應用了CopyOnWriteArrayList,說下它的優缺點:

缺點:安全性高那效率確定就不高,修改代價十分昂貴,每次修改都伴隨着一次的數組複製;但同時優勢也十分明顯,就是在併發下不會產生任何的線程安全問題,也就是絕對的線程安全,這也是爲何咱們要使用CopyOnWriteArrayList的緣由。

優勢:

(1)讀寫分離

咱們讀取CopyOnWriteArrayList的時候讀取的是CopyOnWriteArrayList中的Object[] array,可是修改的時候,操做的是一個新的Object[] array,讀和寫操做的不是同一個對象,這就是讀寫分離。這種技術數據庫用的很是多,在高併發下爲了緩解數據庫的壓力,即便作了緩存也要對數據庫作讀寫分離,讀的時候使用讀庫,寫的時候使用寫庫,而後讀庫、寫庫之間進行必定的同步,這樣就避免同一個庫上讀、寫的IO操做太多

(2)最終一致

對CopyOnWriteArrayList來講,線程1讀取集合裏面的數據,未必是最新的數據。由於線程二、線程三、線程4四個線程都修改了CopyOnWriteArrayList裏面的數據,可是線程1拿到的仍是最老的那個Object[] array,新添加進去的數據並無,因此線程1讀取的內容未必準確。不過這些數據雖然對於線程1是不一致的,可是對於以後的線程必定是一致的,它們拿到的Object[] array必定是三個線程都操做完畢以後的Object array[],這就是最終一致。最終一致對於分佈式系統也很是重要,它經過容忍必定時間的數據不一致,提高整個分佈式系統的可用性與分區容錯性。固然,最終一致並非任何場景都適用的,像火車站售票這種系統用戶對於數據的實時性要求很是很是高,就必須作成強一致性的。

最後總結一點,隨着CopyOnWriteArrayList中元素的增長,CopyOnWriteArrayList的修改代價將愈來愈昂貴,所以,CopyOnWriteArrayList適用於讀操做遠多於修改操做的併發場景中

相關文章
相關標籤/搜索