fast-fail和fast-safe機制
阿新 • • 發佈:2020-07-26
fast-fail(快速失敗)
在使用for迴圈遍歷一個集合時,如果此時改變了集合的結構,如增、刪,則會丟擲ConcurrentModificationException異常。
原因:
- 集合類中有一個
modCount
變數,在向集合中增加或者刪除元素時都會修改這個變數的值; - 每當迭代器使用
hasNext()
/next()
遍歷下一個元素之前都會檢測modCount
變數和expectedModCount
值是否相等; - 如果相等的話就返回遍歷,否則丟擲異常,終止遍歷。
具體程式碼如下:
final void checkForComodification() { if (modCount != expectedModCount) // 1 throw new ConcurrentModificationException(); }
需要注意的是,在序號1處,異常的丟擲條件時檢測到modCount != expectedmodCount
這個條件。如果集合發生變化時修改modCount
值, 剛好有設定為了expectedmodCount
值, 則異常不會丟擲。比如刪除了資料,再新增一條資料。所以不能依賴於這個異常是否丟擲而進行併發操作的程式設計, 這個異常只建議檢測併發修改的bug。
使用場景 :
java.util包下的集合類都是快速失敗機制的, 不能在多執行緒下發生併發修改(迭代過程中被修改).
fail-safe ( 安全失敗 )
採用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先copy原有集合內容,在拷貝的集合上進行遍歷。
原理:
由於迭代時是對原集合的拷貝的值進行遍歷,所以在遍歷過程中對原集合所作的修改並不能被迭代器檢測到,所以不會出發ConcurrentModificationException。
缺點:
基於拷貝內容的優點是避免了ConcurrentModificationException,但同樣地, 迭代器並不能訪問到修改後的內容。 (簡單來說就是, 迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的)
使用場景:
java.util.concurrent包下的容器都是安全失敗的,可以在多執行緒下併發使用,併發修改。