什么是 fail-fast 机制
fail-fast 机制在遍历一个集合时,当集合结构被修改,会抛出 Concurrent Modification Exception。 fail-fast 会在以下两种情况下抛出 ConcurrentModificationException
(1)单线程环境 集合被创建后,在遍历它的过程中修改了结构。
注意 remove() 方法会让 expectModcount 和 modcount 相等,所以是不会抛出这个异常。
(2)多线程环境 当一个线程在遍历这个集合,而另一个线程对这个集合的结构进行了修改。
如下:
- private static void test0() {
- List list = new ArrayList < >();
- list.add("a1");
- list.add("a2");
- list.add("a3");
- list.add("a4");
- list.add("a5");
- list.add("a6");
- list.add("a7");
- list.add("a8");
- for (String s: list) {
- list.remove(s);
- }
- System.out.println(list);
- }
运行会抛出异常
java.util.ConcurrentModificationException
如果又想在遍历的时候做删除操作呢? 借肋 iterator,如下:
- private static void test1() {
- List list = new ArrayList < >();
- list.add("a1");
- list.add("a2");
- list.add("a3");
- list.add("a4");
- list.add("a5");
- list.add("a6");
- list.add("a7");
- list.add("a8");
- Iterator iter = list.iterator();
- while (iter.hasNext()) {
- String str = iter.next();
- System.out.println(str);
- //iter.remove();
- if (Randoms.random(1, 9) % 2 == 0) {
- iter.remove();
- }
- }
- System.out.println(list);
- }
这里我们并没有用 list.remove 元素而是 iter.reomve,但实际 list 中的元素已经被删除也没有抛异常,为什么会这样?
调试的时候我们发现 iter.reomve 执行最终调用的是 ArrayList
public E remove(int index)
所以自然影响了原来的集合。
Iterator 被创建之后会建立一个指向原来对象的单链索引表, 当 list 删除元素里不会影响索引,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
我们再看段代码:
- private static void test2() {
- List list2 = Arrays.asList(new String[] {
- "a1",
- "a2",
- "a3",
- "a4",
- "a5",
- "a6",
- "a7",
- "a8",
- });
- Iterator iter2 = list2.iterator();
- while (iter2.hasNext()) {
- String str = iter2.next();
- System.out.println(str);
- //iter.remove();
- if (Randoms.random(1, 9) % 2 == 0) {
- iter2.remove();
- }
- }
- System.out.println(list2);
- }
结果:
会抛出异常 java.lang.UnsupportedOperationException
为什么呢?感觉跟 test1 是一样的?
我们查看源码 Arrays:
- public static List asList(T...a) {
- return new ArrayList < >(a);
- }
- /**
- * @serial include
- */
- private static class ArrayListextends AbstractListimplements RandomAccess,
- java.io.Serializable {...
- }
发现两个 ArrayList 并不是同一个类却取了同一个名字:
java.util.Arrays.ArrayList!=java.util.ArrayList
你还是你同一个名字却是另一个他....
java.util.Arrays.ArrayList 并没有实现 remove 方法,所以也就抛出了 UnsupportedOperationException 就不足为其了!
看似简单的问题多想一点就好了!
来源: http://www.cnblogs.com/tankaixiong/p/6007093.html