Java中快速失敗和安全失敗
一、快速失敗和安全失敗的環境
快速失敗的環境:java.util包下的容器類都是快速失敗的,不能在多執行緒下對集合進行修改,如果進行修改,則丟擲ConcurrentModificationException異常。
安全失敗的環境:java.util.concurrent包下的容器都是安全失敗,可以在多執行緒下併發使用,併發修改,則不會丟擲ConcurrentModificationException異常。
二、快速失敗(fail-fast):
在使用迭代方式對集合進行遍歷的時候,如果出現A執行緒對集合進行遍歷,而同時又有一個B執行緒對該集合進行一些(增加、刪除、修改)等操作時,此時A執行緒得到的是髒資料(該集合中的元素已經被修改),這個時候,A執行緒就會丟擲ConcurrentModificationException異常,這就是快速失敗。
原理:迭代器在遍歷集合中的元素時,第一次進去就會產生一個modCount、和expectedmodCount的變數,
modCount:用來儲存對集合的修改次數,建立時預設為1次(只要是修改(新增,刪除)了該集合的內容或者遍歷(查詢)了該集合的內容,modCount的次數都會進行+1)
expectedmodCount:僅表示迭代器對集合進行查詢的次數(每查詢一次,expectedmodCount都會+1)
檢視ArrayList集合原始碼的next()方法,原始碼如下
@SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; }
在next()方法中,可以看到在該方法中執行了checkForComodification()方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
我們發現,在checkForComodification()方法中進行了一個modCount和expectedmodCount值的判斷,如果modCount!=expectedmodCount,那麼也就是在A執行緒還在進行迭代的過程中,有其他執行緒對該集合進行修改,這時,A程式就丟擲了ConcurrentModificationException異常。
三、安全失敗(fail-safe)
採用安全失敗機制的集合容器,在遍歷集合時不是直接訪問原來的集合,而是先複製原有集合內容,拷貝一份,然後在複製後的集合上進行遍歷(每次訪問,都會複製,包括修改,刪除)
原理:由於迭代時是對原集合的影印件進行遍歷的,所以在遍歷過程中對原集合所作的修改操作並不能被迭代器檢測到(雖然是髒資料,但還是不會丟擲異常),所以不會觸發ConcurrentModificationException異常,例如CopyOnWriteArrayList集合。
若有不正之處請多多諒解,並歡迎批評指正