前段時間看了ArrayList的源碼,裏面講到Iterator迭代器和快速失敗,安全失敗這塊內容,之前沒碰到過,學習了一番~ 忘了好多,如今總結一下java
(視頻資源:www.bilibili.com/video/BV1gE…)git
Iterator
對象稱爲迭代器(設計模式的一種),迭代器能夠對集合進行遍歷,但每個集合內部的數據結構多是不盡相同的,因此每個集合存和取都極可能是不同的,雖然咱們能夠人爲地在每個類中定義 hasNext()
和 next()
方法,但這樣作會讓整個集合體系過於臃腫。因而就有了迭代器。設計模式
迭代器是將這樣的方法抽取出接口,而後在每一個類的內部,定義本身迭代方式,這樣作就規定了整個集合體系的遍歷方式都是 hasNext()
和next()
方法,使用者不用管怎麼實現的,會用便可。迭代器的定義爲:提供一種方法訪問一個容器對象中各個元素,而又不須要暴露該對象的內部細節。安全
Iterator
主要是用來遍歷集合用的,它的特色是更加安全,由於它能夠確保,在當前遍歷的集合元素被更改的時候,就會拋出 ConcurrentModificationException
異常。markdown
若是單單使用List集合裏的remove方法,會 拋出 ConcurrentModificationException
異常,出現一些問題數據結構
迭代器的默認remove刪除方法 it.remove() 直接刪除(迭代器自帶的remove方法),其實迭代器的remove方法底層仍是用的arraylist的remove方法來刪除元素,可是這個方法中刪除的時候每次都會給預期修改次數的變量進行賦值,因此怎麼都不會產生併發修改異常多線程
快速失敗(fail-fast) 是 Java 集合的一種錯誤檢測機制。在使用迭代器對集合進行遍歷的時候,咱們在多線程下操做非安全失敗(fail-safe)的集合類可能就會觸發 fail-fast 機制,致使拋出 ConcurrentModificationException
異常。 另外,在單線程下,若是在遍歷過程當中對集合對象的內容進行了修改的話也會觸發 fail-fast 機制。併發
注:加強 for 循環也是藉助迭代器進行遍歷。ide
舉個例子:多線程下,若是線程 1 正在對集合進行遍歷,此時線程 2 對集合進行修改(增長、刪除、修改),或者線程 1 在遍歷過程當中對集合進行修改,都會致使線程 1 拋出 ConcurrentModificationException
異常。oop
爲何呢?
每當迭代器使用 hashNext()
/next()
遍歷下一個元素以前,都會檢測 modCount
變量是否爲 expectedModCount
值,是的話就返回遍歷;不然拋出異常,終止遍歷。
若是咱們在集合被遍歷期間對其進行修改的話,就會改變 modCount
的值,進而致使 modCount != expectedModCount
,進而拋出 ConcurrentModificationException
異常。
注:經過
Iterator
的方法修改集合的話會修改到expectedModCount
的值,因此不會拋出異常。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
複製代碼
使用 Iterator
提供的 remove
方法,能夠修改到 expectedModCount
的值。因此,纔不會再拋出ConcurrentModificationException
異常。
明白了快速失敗(fail-fast)以後,安全失敗(fail-safe)咱們就很好理解了。
採用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷。因此,在遍歷過程當中對原集合所做的修改並不能被迭代器檢測到,故不會拋 ConcurrentModificationException
異常。
最後補充一點:迭代器的remove只能解決單線程下的異常拋出問題,多線程的問題仍是得靠使用安全失敗機制的集合容器。
最後,這篇文章只是總結了大概,並無把以前看過的視頻源碼內容所有寫進來,必要時能夠再看一遍視頻,而後看看源碼~