1. 程式人生 > >Java中快速失敗和安全失敗

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集合。

      若有不正之處請多多諒解,並歡迎批評指正