赞
踩
主要靠两个属性:
每次对数组增加或删除元素的时候(注意修改的时候是没有的,这个属性只关注数组长度是否变化)会对数组对象属性modCount做加一操作。
当我们创建一个迭代器对象时,迭代器对象会取当前数组对象属性modCount属性作为默认值存储到迭代器对象里面。
每次迭代器对象往前迭代的时候都要拿自己的对象里面expectedModCount属性跟数组对象的modCount做一次比较,如果相同则代表数据没被改过。如果不同则抛出ConcurrentModificationException。
注意:这里只能解决在遍历时,不能对数据做增加或删除修改,对多线程并不是安全的。
下面看下代码。
...
protected transient int modCount = 0;
...
看下这个属性主要在哪些地方会被使用
//以删除为例子 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; }
OK,下面先跑出异常
public static void main(String[] args) { List<Integer> a = new ArrayList<>(); a.add(1); a.add(1); a.add(1); a.add(1); a.add(1); for(Integer n:a){ a.remove(0); } } // Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at bingo.galink.ability.boot.Test.main(Test.java:18)
直接定位到迭代器对象的checkForComodification方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
OK,在这里我们就可以看到当迭代器对象里面expectedModCount跟当前数组对象的modCount不一样时(remove的时候改变了modCount),就会出现这个异常。
那解决的方法也很简单,就是避免在多线程下、在for-in语法下对同一数组做遍历删除操作。
使用迭代器里面访问,使用迭代器的remove方法进行删除
public static void main(String[] args) { List<Integer> a = new ArrayList<>(); a.add(1); a.add(1); a.add(1); a.add(1); a.add(1); Iterator<Integer> i = a.iterator(); while (i.hasNext()){ i.next(); i.remove(); } // for(Integer n:a){ // a.remove(0); // } }
最后再看看为什么这样是行的
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();
}
}
此时,访问数组对象只有迭代器自己,所以先做了checkForComodification判断,肯定是成功的,因为数组对象的modCount并没有改变。然后再通过迭代器本身去删除值,并修改迭代器对象的内部属性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。