快速失敗(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