浅谈fail-fast机制
fail-fast机制即为快速失败机制,个人认为是一种防护措施,在集合结构发生改变的时候,使尽全力抛出concurrentmodificationexception,所以该机制大部分用途都是用来检测bug的;
下面的代码可以引发fail-fast
1 public static void main(string[] args) { 2 list<string> list = new arraylist<>(); 3 for (int i = 0 ; i < 10 ; i++ ) { 4 list.add(i + ""); 5 } 6 iterator<string> iterator = list.iterator(); 7 int i = 0 ; 8 while(iterator.hasnext()) { 9 if (i == 3) { 10 list.remove(3); 11 //list.add("11"); 添加元素同样会引发 12 } 13 system.out.println(iterator.next()); 14 i ++; 15 } 16 }
fail-fast原理
每个集合都会实现可遍历的接口,以上述代码为例,集合调用iterator();方法的时候,其实是返回了一个new itr();
/** * returns an iterator over the elements in this list in proper sequence. * * <p>the returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public iterator<e> iterator() { return new itr(); }
以下是itr源码
/** * an optimized version of abstractlist.itr */ 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 = arraylist.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 { arraylist.this.remove(lastret); cursor = lastret; lastret = -1; expectedmodcount = modcount; } catch (indexoutofboundsexception ex) { throw new concurrentmodificationexception(); } } @override @suppresswarnings("unchecked") public void foreachremaining(consumer<? super e> consumer) { objects.requirenonnull(consumer); final int size = arraylist.this.size; int i = cursor; if (i >= size) { return; } final object[] elementdata = arraylist.this.elementdata; if (i >= elementdata.length) { throw new concurrentmodificationexception(); } while (i != size && modcount == expectedmodcount) { consumer.accept((e) elementdata[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastret = i - 1; checkforcomodification(); } final void checkforcomodification() { if (modcount != expectedmodcount) throw new concurrentmodificationexception(); } }
itr有3个重要属性;
cursor是指集合遍历过程中的即将遍历的元素的索引
lastret是cursor -1,默认为-1,即不存在上一个时,为-1,它主要用于记录刚刚遍历过的元素的索引。
expectedmodcount它初始值就为arraylist中的modcount(modcount是抽象类abstractlist中的变量,默认为0,而arraylist 继承了abstractlist ,所以也有这个变量,modcount用于记录集合操作过程中作的修改次数)
由源码可以看出,该异常就是在调用next()的时候引发的,而调用next()方法的时候会先调用checkforcomodification(),该方法判断expectedmodcount与modcount是否相等,如果不等则抛异常了
那么问题就来了,初始化的时候expectedmodcount就被赋值为modcount,而且源码当中就一直没有改变过,所以肯定是modcount的值变了
arraylist继承了abstractlist,abstractlist有modcount属性,通过以下源码我们可以看到,当arraylist调用add、remove方法,modcount++
/** * inserts the specified element at the specified position in this * list. shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws indexoutofboundsexception {@inheritdoc} */ public void add(int index, e element) { rangecheckforadd(index); ensurecapacityinternal(size + 1); // increments modcount!! system.arraycopy(elementdata, index, elementdata, index + 1, size - index); elementdata[index] = element; size++; } /** * removes the element at the specified position in this list. * shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws indexoutofboundsexception {@inheritdoc} */ public e remove(int index) { rangecheck(index); modcount++; e oldvalue = elementdata(index); 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 return oldvalue; }
所以由此可见,对集合的操作中若modcount发生了改变,则会引发fail-fast机制;同时可以看出如果想要移除集合某元素,可以使用迭代器的remove方法,则不会引发fail-fast;
发表该文章也参考了许多另一片文章的内容,详情地址:https://blog.csdn.net/zymx14/article/details/78394464
上一篇: cent os 上安装 matlab
下一篇: Android中对已安装应用的管理实现