在 Doug Lea 的 Concurrent Programming in Java一書的第 2 章第 2.4.4 節(請參閱
參考資料)中,對 copy-on-write 模式作了最好的描述。實質上,這個模式聲明了,為了維護對象的一致性快照,要依靠不可變性(immutability)來消除在協調讀取不同的但是相關的屬性時需要的同步。對於集合,這意味著如果有大量的讀(即get() ) 和迭代,不必同步操作以照顧偶爾的寫(即
add() )調用。對於新的 CopyOnWriteArrayList 和CopyOnWriteArraySet 類,所有可變的(mutable)操作都首先取得後台數組的副本,對副本變更,然後替換副本。這種做法保證了在遍曆自身更改的集合時,永遠不會拋出ConcurrentModificationException 。遍曆集合會用原來的集合完成,而在以後的操作中使用更新後的集合。
在讀和寫都存在,而寫的情況較少,大多數時候都是讀的情況下,可以對當前
集合copy副本,寫副本,讀取當前集合,後續操作中副本替換當前集合。保證讀和寫不衝突。
這些新的集合, CopyOnWriteArrayList 和 CopyOnWriteArraySet ,最適合於讀操作通常大大超過寫操作的情況。一個最常提到的例子是使用監聽器列表。已經說過,Swing 組件還沒有改為使用新的集合。相反,它們繼續使用javax.swing.event.EventListenerList 來維護它們的監聽器列表。
如清單 6 所示,集合的使用與它們的非 copy-on-write 替代物完全一樣。只是建立集合并在其中加入或者刪除元素。即使對象加入到了集合中,原來的
Iterator 也可以進行,繼續遍曆原來集合中的項。
/**
* 註冊一個事件監聽者
* @param listener
*/
private void registerEventListener(String eventType, EventListener listener) {
Set<EventListener> set = listeners.get(eventType);
if (set == null) {
set = new CopyOnWriteArraySet<EventListener>();
listeners.put(eventType, set);
}
set.add(listener);
if(!EventContext.dispatchers.contains(this)) {
EventContext.dispatchers.add(this);
}
}