1. 程式人生 > >Copy-On-Write寫時複製機制與Java中CopyOnWriteArrayList容器原始碼實現

Copy-On-Write寫時複製機制與Java中CopyOnWriteArrayList容器原始碼實現

Copy-on-Write機制簡稱COW,是一種併發設計策略。其基本思路是多執行緒同時共享同一個內容,當某個執行緒想要修改這個內容的時候,才會真正的把內容copy出去形成一個新的內容然後修改,其它的執行緒繼續讀舊的內容,直到修改完成。這是一種延時懶惰策略。
Copy-on-Write有那麼幾個應用場景:

  • linux系統中記憶體的管理和分配。參考:寫時複製機制
  • redis快照持久化(bgm)時,會fork出一個子程序進行持久化操作,當主程序接收到寫操作時,會copy出一份新的記憶體,對新的記憶體進行寫操作。
  • jdk1.5引入了juc包下的CopyOnWriteArrayList和CopyOnWriteArraySet。

我們這裡來看下CopyOnWriteArrayList原始碼。在向ArrayList中新增元素時,是要加鎖的,否則多執行緒寫就會Copy出N個副本出來。

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    //寫時需要加鎖
    final transient ReentrantLock lock = new ReentrantLock();

    //在修改之後需要保證其他讀執行緒能立刻讀到新資料
private transient volatile Object[] array; final Object[] getArray() { return array; } final void setArray(Object[] a) { array = a; } //增加元素時需要加鎖 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(); } } //獲取陣列中的元素,一律從舊的陣列中讀 public E get(int index) { return get(getArray(), index); } }

存在問題:

在進行寫時複製時,會存在兩份記憶體,將會佔用兩倍的記憶體空間,所以需要對記憶體進行精確的統計,要保證系統記憶體不會溢位。