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