Copy-On-Write寫時複製機制與Java中CopyOnWriteArrayList容器原始碼實現
阿新 • • 發佈:2018-11-12
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);
}
}
存在問題:
在進行寫時複製時,會存在
兩份記憶體
,將會佔用兩倍的記憶體空間,所以需要對記憶體進行精確的統計,要保證系統記憶體不會溢位。