java的快速失敗和安全失敗
java的快速失敗和安全失敗
一:快速失敗(fail—fast)
在用迭代器遍歷一個集合物件時,如果遍歷過程中對集合物件的內容進行了修改(增加、刪除、修改),則會丟擲Concurrent Modification Exception。
原理:迭代器在遍歷時直接訪問集合中的內容,在遍歷過程中使用一個 modCount 變數和expectedmodCount變數。
//用來記錄List修改的次數
protected transient int modCount=0;
//修改數的記錄值
int expectedModCount=modCount;
每次修改List集合中的元素時都會比較expectedModCount和modCount是否相等,如果不相等就會丟擲ConcurrentModificationException異常。
在某一時刻,“執行緒a”建立了arrayList的Iterator。建立時expectedModCount=modCount(假設它們的值為N),
在“執行緒a”遍歷arrayList的某一時刻,“執行緒b”對arrayList中的元素進行了刪除或者其他的修改,在remove()方法中執行“modCount++”,則modCount=N+1,但“執行緒a”繼續遍歷時執行next()方法時,判斷expectedModCount是否等於modCount,這時modCount=N+1而expectedModCount=N,所以丟擲ConcurrentModificationException異常,產生fail—fast事件。
解決方法:將ArrayList替換成java.util.concurrent包下對應的類
二:安全失敗(fail—safe)
採用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷。簡單來說就是在“執行緒a”對原集合(集合1)進行遍歷時,先複製出一個新集合(集合2),在用集合2進行遍歷,“執行緒b”在“執行緒a”遍歷時進行修改,也是複製一個新的集合(集合3),然後在集合3上進行修改,在修改完後將原集合的引用指向新集合也就是集合3。
優點:讀寫分離,避免了Concurrent Modification Exception。
缺點:迭代器不能訪問修改後的內容,在遍歷期間發生的修改迭代器是不知道的。