我們來聊聊快速失敗和安全失敗

 一:快速失敗(fail—fast)

在用迭代器遍歷一個集合對象時,若是遍歷過程當中對集合對象的內容進行了修改(增長、刪除、修改),則會拋出Concurrent Modification Exception。java

原理:迭代器在遍歷時直接訪問集合中的內容,而且在遍歷過程當中使用一個 modCount 變量。
集合在被遍歷期間若是內容發生變化,就會改變modCount的值。每當迭代器使用hashNext()/next()遍歷下一個元素以前,
都會檢測modCount變量是否爲expectedmodCount值,是的話就返回遍歷;不然拋出異常,終止遍歷。複製代碼

注意:這裏異常的拋出條件是檢測到 modCount!=expectedmodCount 這個條件。若是集合發生變化時修改modCount值恰好又設置爲了expectedmodCount值,則異常不會拋出。所以,不能依賴於這個異常是否拋出而進行併發操做的編程,這個異常只建議用於檢測併發修改的bug。編程

fail-fast的出現場景安全

1529652624(1)

二:安全失敗(fail—safe)

採用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷。bash

原理:因爲迭代時是對原集合的拷貝進行遍歷,因此在遍歷過程當中對原集合所做的修改並不能被迭代器檢測到,因此不會觸發Concurrent Modification Exception。多線程

缺點:基於拷貝內容的優勢是避免了Concurrent Modification Exception,但一樣地,迭代器並不能訪問到修改後的內容,即:迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的。併發

場景:java.util.concurrent包下的容器都是安全失敗,能夠在多線程下併發使用,併發修改。ui

相關文章
相關標籤/搜索