Java中fail-fast和fail-safe

1.同步修改

    當一個或多個線程正在遍歷一個集合Collection,此時另一個線程修改了這個集合的內容,就是併發修改。

2.什麼是fail-fast機制?

    fail-fast機制在遍歷一個集合時,當集合機構被修改,會拋出Concurrent Modification Exception

    fail-fast會在以下兩種情況拋出ConcurrentModificationException

   (1) 單線程情況

    集合被創建後,在遍歷它的過程中修改了結構。注意remove()方法會讓expectModCount和modCount相等,因此不會拋出這個異常

(2)多線程環境

    當一個線程在遍歷集合,另一個線程對集合的機構進行了修改

3.fail-fast機制是如何檢測?

    迭代器在遍歷過程中是直接訪問內部數據的,因此內部的數據在遍歷的過程中無法被修改。爲了保證不被修改,迭代器內部維護了一個標記 “mode” ,當集合結構改變(添加刪除或者修改),標記"mode"會被修改,而迭代器每次的hasNext()和next()方法都會檢查該"mode"是否被改變,當檢測到被修改時,拋出Concurrent Modification Exception。下面看ArrayList迭代器的部分源碼

private class Itr implements Iterator<E> {
        int cursor;
        int lastRet = -1;
        int expectedModCount = ArrayList.this.modCount;
 
        public boolean hasNext() {
            return (this.cursor != ArrayList.this.size);
        }
 
        public E next() {
            checkForComodification();
            /** 省略此處代碼 */
        }
 
        public void remove() {
            if (this.lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
            /** 省略此處代碼 */
        }
 
        final void checkForComodification() {
            if (ArrayList.this.modCount == this.expectedModCount)
                return;
            throw new ConcurrentModificationException();
        }
}

可以看到它的標記“mode”爲 expectedModeCount

4.fail-safe機制

fail-safe任何對集合結構的修改都會在一個複製的集合上進行修改,因此不會拋出ConcurremtModificationException

fail-safe機制有兩個問題

(1)需要複製集合,產生大量的無效對象,開銷大

(2)無法保證讀取的數據是目前原始數據結構中的數據。

5.fail-fast和fail-safe的例子

(1) fail-fast例子

public class FailFastExample
{
    
    
    public static void main(String[] args)
    {
        Map<String,String> premiumPhone = new HashMap<String,String>();
        premiumPhone.put("Apple", "iPhone");
        premiumPhone.put("HTC", "HTC one");
        premiumPhone.put("Samsung","S5");
        
        Iterator iterator = premiumPhone.keySet().iterator();
        
        while (iterator.hasNext())
        {
            System.out.println(premiumPhone.get(iterator.next()));
            premiumPhone.put("Sony", "Xperia Z");
        }
        
    }
    
}

輸出

iPhone

Exception in thread "main" java.util.ConcurrentModificationException

      at java.util.HashMap$HashIterator.nextEntry(Unknown Source)

      at java.util.HashMap$KeyIterator.next(Unknown Source)

      at FailFastExample.main(FailFastExample.java:20)

(2)fail-safe例子

public class FailSafeExample
{
    
    
    public static void main(String[] args)
    {
        ConcurrentHashMap<String,String> premiumPhone = 
                               new ConcurrentHashMap<String,String>();
        premiumPhone.put("Apple", "iPhone");
        premiumPhone.put("HTC", "HTC one");
        premiumPhone.put("Samsung","S5");
        
        Iterator iterator = premiumPhone.keySet().iterator();
        
        while (iterator.hasNext())
        {
            System.out.println(premiumPhone.get(iterator.next()));
            premiumPhone.put("Sony", "Xperia Z");
        }
        
    }
    
}

輸出

S5

HTC

one iPhone

6.fail-fast和fail-safe區別

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