CopyOnWriteArrayList

CopyOnWriteArrayList

寫入時複製(CopyOnWrite)思想

  寫入時複製(CopyOnWrite,簡稱COW)思想是計算機程序設計領域中的一種優化策略。其核心思想是,若是有多個調用者(Callers)同時要求相同的資源(如內存或者是磁盤上的數據存儲),他們會共同獲取相同的指針指向相同的資源,直到某個調用者試圖修改資源內容時,系統纔會真正複製一份專用副本(private copy)給該調用者,而其餘調用者所見到的最初的資源仍然保持不變。這過程對其餘的調用者都是透明的(transparently)。此作法主要的優勢是若是調用者沒有修改資源,就不會有副本(private copy)被建立,所以多個調用者只是讀取操做時能夠共享同一份資源。數組

歸納一下CopyOnWriteArrayList源碼註釋介紹了什麼:安全

  1. CopyOnWriteArrayList是線程安全容器(相對於ArrayList),底層經過複製數組的方式來實現。
  2. CopyOnWriteArrayList在遍歷的使用不會拋出ConcurrentModificationException異常,而且遍歷的時候就不用額外加鎖
  3. 元素能夠爲null
  4. CopyOnWriteArrayList底層就是數組,加鎖就交由ReentrantLock來完成
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;
        
        // 將volatile Object[] array 的指向替換成新數組
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

====在添加的時候就上鎖,並複製一個新數組,增長操做在新數組上完成,將array指向到新數組中,最後解鎖。
對於remove()、clear()set()和add()是相似的優化

部分源碼:this

/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();

/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
/**
 * Gets the array.  Non-private so as to also be accessible
 * from CopyOnWriteArraySet class.
 */
final Object[] getArray() {
    return array;
}
/**
 * Sets the array.
 */
final void setArray(Object[] a) {
    array = a;
}

array 數組是被 volatile修飾的,修改後其餘線程可當即察覺到這個修改spa

volatile :(揮發物、易變的):變量修飾符,只能用來修飾變量。修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。並且,當成員變量發生變 化時,強迫線程將變化值回寫到共享內存。這樣在任什麼時候刻,兩個不一樣的線程老是看到某個成員變量的同一個值。
transient:(暫短的、臨時的):修飾符,只能用來修飾字段。在對象序列化的過程當中,標記爲transient的變量不會被序列化。線程

總結:設計

  • 在修改時,複製出一個新數組,修改的操做在新數組中完成,最後將新數組交由array變量指向
  • 寫加鎖,讀不加鎖

缺點:指針

  • 內存佔用:若是CopyOnWriteArrayList常常要增刪改裏面的數據,常常要執行add()、set()、remove()的話,那是比較耗費內存的
  • 數據一致性問題。CopyOnWrite容器只能保證數據的最終一致性,不能保證數據的實時一致性
相關文章
相關標籤/搜索