首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

java.util.ConcurrentModificationException 出现的原因和解决方法

2012-11-06 
java.util.ConcurrentModificationException 出现的原因和解决办法?public static void main(String[] arg

java.util.ConcurrentModificationException 出现的原因和解决办法

?

public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); list.add("7"); List<String> del = new ArrayList<String>(); del.add("5"); del.add("6"); del.add("7"); for(String str : list){ if(del.contains(str)) { list.remove(str); } } }

Exception in thread "main" java.util.ConcurrentModificationException

public Iterator<E> iterator() {   return new Itr();}

?

private class Itr implements Iterator<E> {/** * Index of element to be returned by subsequent call to next. */int cursor = 0;/** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */int lastRet = -1;/** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */int expectedModCount = modCount;public boolean hasNext() { return cursor != size();}public E next() { checkForComodification(); //检测modCount和expectedModCount的值!! try {E next = get(cursor);lastRet = cursor++;return next; } catch (IndexOutOfBoundsException e) {checkForComodification();throw new NoSuchElementException(); }}public void remove() { if (lastRet == -1)throw new IllegalStateException(); checkForComodification(); try {AbstractList.this.remove(lastRet); //执行remove的操作if (lastRet < cursor) cursor--;lastRet = -1;expectedModCount = modCount; //保证了modCount和expectedModCount的值的一致性,避免抛出ConcurrentModificationException异常 } catch (IndexOutOfBoundsException e) {throw new ConcurrentModificationException(); }}final void checkForComodification() { if (modCount != expectedModCount) //当modCount和expectedModCount值不相等时,则抛出ConcurrentModificationException异常throw new ConcurrentModificationException();} }

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 remove method that skips bounds checking and does not * return the value removed. */ private void fastRemove(int index) { modCount++; //只是修改了modCount,因此modCount将与expectedModCount的值不一致 int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work } ?

public E next() { checkForComodification(); //检测modCount和expectedModCount的值!! try {E next = get(cursor);lastRet = cursor++;return next; } catch (IndexOutOfBoundsException e) {checkForComodification();throw new NoSuchElementException(); }} final void checkForComodification() { if (modCount != expectedModCount) //当modCount和expectedModCount值不相等时,则抛出ConcurrentModificationException异常throw new ConcurrentModificationException();} }

List<String> save = new ArrayList<String>(); for(String str : list) { if(del.contains(str)) { save.add(str); } } list.removeAll(save);?

 Iterator<String> iterator = list.iterator(); while(iterator.hasNext()) { String str = iterator.next(); if(del.contains(str)) { iterator.remove(); } }

? ? ??Iterator.remove()方法保证了modCount和expectedModCount的值的一致性,避免抛出ConcurrentModificationException异常。

?

不过对于在多线程环境下对集合类元素进行迭代修改操作,最好把代码放在一个同步代码块内,这样才能保证modCount和expectedModCount的值的一致性,类似如下:

?

Iterator<String> iterator = list.iterator();  synchronized(synObject) { while(iterator.hasNext()) {           String str = iterator.next();           if(del.contains(str)) {               iterator.remove();           }       }  }    
?

因为迭代器实现类如:ListItr的next(),previous(),remove(),set(E e),add(E e)这些方法都会调用checkForComodification(),源码:

?

final void checkForComodification() {    if (modCount != expectedModCount)throw new ConcurrentModificationException();}
?

?

?

?

?

?

曾经写了下面这段对HashMap进行迭代删除操作的错误的代码:

?

Iterator<Integer> iterator = windows.keySet().iterator();while(iterator.hasNext()) {int type = iterator.next();windows.get(type).closeWindow();iterator.remove();windows.remove(type);//}

?

?上面的代码也会导致ConcurrentModificationException的发生。罪魁祸首是windows.remove(type);这一句。

根据上面的分析我们知道iterator.remove();会维护modCount和expectedModCount的值的一致性,而windows.remove(type);这句是不会的。其实这句是多余的,上面的代码去掉这句就行了。

iterator.remove()的源码如下:HashIterator类的remove()方法

?

?

 public void remove() {            if (lastEntryReturned == null)                throw new IllegalStateException();            if (modCount != expectedModCount)                throw new ConcurrentModificationException();            HashMap.this.remove(lastEntryReturned.key);            lastEntryReturned = null;            expectedModCount = modCount; //保证了这两值的一致性        }

?HashMap.this.remove(lastEntryReturned.key);这句代码说明windows.remove(type);是多余的,因为已经删除了该key对应的value。

windows.remove(type)的源码:

public V remove(Object key) { if (key == null) { return removeNullKey(); } int hash = secondaryHash(key.hashCode()); HashMapEntry<K, V>[] tab = table; int index = hash & (tab.length - 1); for (HashMapEntry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && key.equals(e.key)) { if (prev == null) { tab[index] = e.next; } else { prev.next = e.next; } modCount++; size--; postRemove(e); return e.value; } } return null; }

private V removeNullKey() { HashMapEntry<K, V> e = entryForNullKey; if (e == null) { return null; } entryForNullKey = null; modCount++; size--; postRemove(e); return e.value; }

?

热点排行