fail-fast 與 fail-safe

快速失敗(fail-fast)與安全失敗(fail-safe)java

fail-fast:當再遍歷集合(以非線程安全的HashMap爲例)的時候,若是監測到modCount值發變化,則直接拋出ConcurrentModificationException的異常,若是是使用迭代器遍歷時修改,會在第一次的時候將異常拋出,若是是用forEach循環的話,則會在執行完全部的代碼後再拋出異常(之前的for(Object object : list)的語法方式,通過編譯以後變成迭代器iterator,但java8的foreach編譯以後並不會變成迭代器iterator,而是編譯後的結果與編寫時幾乎同樣,因此java8的foreach可能不是純粹是語法糖)安全

HashMap<Integer, Integer> hashMap = new HashMap();
        hashMap.put(1, 1);
        hashMap.put(2, 2);
        hashMap.put(3, 3);

        // 測試一,當執行第一個的時候就會報錯,不會執行下一個
        Set set = hashMap.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            hashMap.put(10, 10);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        }
        // 測試一結果:
//        1=1
//        此時 hashMap 長度爲4
//        java.util.ConcurrentModificationException

        // 測試二,用原始的for循環進行遍歷,測試結果同測試一,緣由其實時for是語法糖,編譯後就會變化迭代器
        Set<Integer> keySet = hashMap.keySet();
        for (Integer index : keySet) {
            System.out.println(hashMap.get(index));
            hashMap.put(10, 10);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        }

        // 測試三,會執行完for的全部代碼,最後再拋出異常,java8的循環已經不一樣於迭代器
        hashMap.forEach((o, o2) -> {
            System.out.println(String.valueOf(o) + String.valueOf(o2));
            hashMap.put(4, 4);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        });

        // 測試三結果:
//        11
//        此時 hashMap 長度爲4
//        22
//        此時 hashMap 長度爲4
//        33
//        此時 hashMap 長度爲4
//        44
//        此時 hashMap 長度爲4
//        java.util.ConcurrentModificationException

fail-safe(針對線程安全的集合,例如:ConcurrentHashMap)測試

網上解釋:當在作遍歷的時候,集合會複製出一份,再作遍歷,這樣即便原集合作了修改,也不會影響當前遍歷,即遍歷有三個元素的集合,在遍歷期間,添加了一個元素,在遍歷過程當中,添加後的元素不會被遍歷到線程

但我測試以後好像不是這樣的,可能時jdk版本的問題吧,個人jdk版本時1.8.0_152code

ConcurrentHashMap<Integer, Integer> hashMap = new ConcurrentHashMap<>();
        hashMap.put(1, 1);
        hashMap.put(2, 2);
        hashMap.put(3, 3);

        // 測試一,在遍歷期間會將添加的元素加進去,但不會拋異常,與網上的說法有些不一致,網上說法時不會理會遍歷期間添加的元素
        Set set = hashMap.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            hashMap.put(10, 10);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        }
        // 測試一結果:
//        1=1
//        此時 hashMap 長度爲4
//        2=2
//        此時 hashMap 長度爲4
//        3=3
//        此時 hashMap 長度爲4
//        10=10
//        此時 hashMap 長度爲4

        // 測試二, 結果同一
        Set<Integer> keySet = hashMap.keySet();
        for (Integer index : keySet) {
            System.out.println(hashMap.get(index));
            hashMap.put(10, 10);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        }

        // 測試三,
        hashMap.forEach((o, o2) -> {
            System.out.println(String.valueOf(o) + String.valueOf(o2));
            hashMap.put(4, 4);
            System.out.println("此時 hashMap 長度爲" + hashMap.size());
        });

        // 測試三結果:
//        11
//        此時 hashMap 長度爲4
//        22
//        此時 hashMap 長度爲4
//        33
//        此時 hashMap 長度爲4
//        44
//        此時 hashMap 長度爲4
相關文章
相關標籤/搜索