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、同步控制,保证只有一个线程能访问集合;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)