1. 程式人生 > 實用技巧 >fast-fail和fast-safe機制

fast-fail和fast-safe機制

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包下的容器都是安全失敗的,可以在多執行緒下併發使用,併發修改。