JavaSE---Fail-Fast

总结

  主要用于集合类中,以确保 在遍历集合时如果集合本身被修改,则会立即抛出ConcurrentModificationException异常。

原理

  • 内部计数器:每个集合对象都有一个内部计数器,称为modCount(modification count)。每当集合结构被修改(比如添加或删除元素),这个计数器就会增加。
  • 迭代器检查:当通过迭代器遍历集合时,迭代器会在每次调用next()方法之前检查当前的modCount是否与创建迭代器时的expectedModCount相匹配。如果不匹配,说明集合已经被修改了,这时迭代器就会抛出ConcurrentModificationException

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
 
        transient Object[] elementData;
        private int size;
         
        // add
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;                                                        // size ++
            return true;
        }
 
        private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
 
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;                                                                     // modCount++
 
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
 
        // remove
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
 
        private void fastRemove(int index) {
            modCount++;                                                                 // modCount++
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index, numMoved);
            elementData[--size] = null; // clear to let GC do its work                  // --size
        }
 
        private class Itr implements Iterator<E> {
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            int expectedModCount = modCount;
 
            public boolean hasNext() {
                return cursor != size;
            }
 
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
 
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
 
                try {
                    this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
 
            final void checkForComodification() {
                if (modCount != expectedModCount)                       // modCount与expectedModCount比较
                    throw new ConcurrentModificationException();
            }
        }
    }

  

示例

单线程

  当使用iterator遍历List & 使用List的remove,将会ConcurrentModificationException;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");
        list.add("Banana");
         
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            // 在遍历过程中修改集合
            if ("Banana".equals(fruit)) {
                list.remove(fruit);
            }
        }
        System.out.println(list);

  list的remove会修改modCount,导致modCount 与 expectedModCount不相等;

 

解决  

1、使用iterator遍历时,使用iterator的remove,将不会修改modCount;

2、多线程环境,使用线程安全集合类;

3、同步控制,保证只有一个线程能访问集合;

posted on   anpeiyong  阅读(7)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示