java並發容器CopyOnWriteArrayList
CopyOnWriteArrayList
顧名思義,當數組有變化時重新建立一個新的數組
其設計是對於線程安全容器Vector使用中出現問題的一種解.
在Vector容器中,當需要執行復合操作
例如:
//代碼1
class Observable { private List<Observer> observers=new Vector<Observer>(); public void addObserver(){...} public void removeObserver(){...} public void notify() { Iterator<Observer> itr=observers.iterator(); while(itr.hasNext()){ Observer observer=itr.next(); observer.notify(); } return; } }
Observable中的notify方法在單線程中的實現是正常的,但在多線程中,由於在notify執行過程中observers數組的內容可能會發生改變,導致遍歷失效.即使observers本身是線程安全的也於是無補
通常解決這個問題,可以使用同步方法或者加鎖
//代碼2
class Observable
{
private List<Observer> observers=new Vector<Observer>();
public synchronized void addObserver(){...}
public synchronized void removeObserver(){...}
//同步方法
public synchronized void notify()
{
Iterator<Observer> itr=observers.iterator();
while(itr.hasNext()){
Observer observer=itr.next();
observer.notify();
}
return;
}
}
這樣的解決方案中notify的同步導致另外一個問題,即活躍性問題.當observers中有很多元素或者每一個元素的notify方法調用需要很久時,此方法將長時間持有鎖.導致其他任何想修改observers的行為阻塞.最后嚴重影響程序性能
CopyOnWriteArrayList即在這種場景下使用.一個需要在多線程中操作,並且頻繁遍歷.
其解決了由於長時間鎖定整個數組導致的性能問題.
其解決方案即寫時拷貝。
我們先來貼出使用CopyOnWriteArrayList的Observable代碼
//代碼3
class Observable { private List<Observer> observers=new CopyOnWriteArrayList<Observer>(); public void addObserver(){...} public void removeObserver(){...} public void notify() { Iterator<Observer> itr=observers.iterator(); while(itr.hasNext()){ Observer observer=itr.next(); observer.notify(); } return; } }
Observable的notify方法和代碼1相同.但其不會有多線程同時操作的問題.其中的奧秘,通過分析源碼可知
當CopyOnWriteArrayList添加或者刪除元素時,其實現為根據當前數組重新建立一個新數組..
Iterator<Observer> itr=observers.iterator();
當我們獲取CopyOnWriteArrayList的迭代器時,迭代器內保存當前數組的引用.之后如果別的線程改變CopyOnWriteArrayList中元素,則根據CopyOnWriteArrayList的特性,其實並沒有改變這個迭代器指向數組的內容.
如圖

