快速失敗 (fail-fast) 和安全失敗 (fail-safe) 的區別是什麼?

快速失敗 (fail-fast) 和安全失敗 (fail-safe) 的區別是什麼?

什麼是快速失敗

快速失敗(fail-fast) 是指當多個線程對同一個Collection進行操作時,其中一個線程通過iterator去遍歷集合時,該集合內容被另一個集合改變;則產生快速失敗,會拋出ConcurrentModifycationException異常。

快速失敗原理:

以ArrayList爲例,ArrayList的iterator是在父類AbstractList中實現的。AbstractList中有唯一屬性modCount,用來記錄list修改的次數。在Iterator的實現類Itr中將modCount保存到exceptedModCount中,以後每次遍歷List中的元素的時候,都會比較expectedModCount和modCount是否相等;若不相等,則拋出ConcurrentModificationException異常,產生fail-fast事件。通過Itr,我們知道:expectedModCount不可能被修改爲不等於 modCount。所以,需要考證的就是modCount何時會被修改。接下來,我們查看ArrayList的源碼,可以發現無論是add()、remove(),還是clear(),只要涉及到修改集合中的元素個數時,都會改變modCount的值。

總結一下:

當多個線程對同一個集合進行操作的時候,某線程訪問集合的過程中,該集合的內容被其他線程所改變(即其它線程通過add、remove、clear等方法,改變了modCount的值);這時,就會拋出ConcurrentModificationException異常,產生fail-fast事件。
java.util包下的集合類都是快速失敗的,不能在多線程下發生併發修改(迭代過程中被修改)。

fail-fast解決方法:

通過util.concurrent集合包下的相應類去處理,則不會產生fail-fast事件。如使用ArrayList會產生fail-fast,使用CopyOnWriteArrayList則不會。

安全失敗(fail-safe)原理:

迭代時是對原集合的拷貝進行遍歷,所以在遍歷過程中對原集合所作的修改並不能被迭代器檢測到,所以不會觸發Concurrent Modification Exception。因此缺點就是,迭代器並不能訪問到修改後的內容,即:迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的。

區別:
Fail Fast Fail Safe
拋出ConcurrentModificationException異常 ×
拷貝原集合 ×
內存開銷 ×
栗子 HashMap、Vector、ArrayList、HashList CopyOnWriteArrayList、ConcurrentHashMap

參考博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章