天天看點

Java 的快速失敗和安全失敗

參考1

參考2

一、快速失敗(fail—fast)

在用疊代器周遊一個集合對象時,如果周遊過程中對集合對象的内容進行了修改(增加、删除、修改),則會抛出 Concurrent Modification Exception。

原理:疊代器在周遊時直接通路集合中的内容,并且在周遊過程中使用一個 modCount 變量。集合在被周遊期間如果内容發生變化,就會改變 modCount 的值。每當疊代器使用 hashNext()/next() 周遊下一個元素之前,都會檢測 modCount 變量是否為 expectedmodCount 值,是的話就傳回周遊;否則抛出異常,終止周遊。

注意:這裡異常的抛出條件是檢測到 modCount != expectedmodCount 這個條件。如果集合發生變化時修改 modCount 值剛好又設定為了 expectedmodCount 值,則異常不會抛出。是以,不能依賴于這個異常是否抛出而進行并發操作的程式設計,這個異常隻建議用于檢測并發修改的 bug。

場景:java.util 包下的集合類都是快速失敗的,不能在多線程下發生并發修改(疊代過程中被修改)。

二、安全失敗(fail—safe)

采用安全失敗機制的集合容器,在周遊時不是直接在集合内容上通路的,而是先複制原有集合内容,在拷貝的集合上進行周遊。

原理:由于疊代時是對原集合的拷貝進行周遊,是以在周遊過程中對原集合所作的修改并不能被疊代器檢測到,是以不會觸發 Concurrent Modification Exception。

缺點:基于拷貝内容的優點是避免了 Concurrent Modification Exception,但同樣地,疊代器并不能通路到修改後的内容,即:疊代器周遊的是開始周遊那一刻拿到的集合拷貝,在周遊期間原集合發生的修改疊代器是不知道的。

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