java.util.ConcurrentModificationException原因及解决

上一篇 / 下一篇  2011-12-23 16:29:34 / 个人分类:开发知识

java.util.ConcurrentModificationException解决办法

HashMap<String,String> map=new HashMap<String,String>();

map.put("key1", "value1");

map.put("key2", "value2");

map.put("key3", "value3");

System.out.println(map.size());

Iterator<Entry<String, String>> it = map.entrySet().iterator();

while(it.hasNext()){

Map.Entry<String,String> entry = it.next();

String key=(String)entry.getKey();

if(key.equals("key3"))

map.remove(key); (用这句话就出错)

//it.remove();(用这句话不会出错)
System.out.println(key);
}

(这个是从网上找的)网 上查找的关于Iterator的工作机制。Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。List、Set等是动态的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,不能逆序操作的数据结构,当 Iterator指向的原始数据发生变化时,Iterator自己就迷失了方向。

下面代码来自源码util的HashMap.java
hashmap进行remove的源码:
    public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);
        return (e == null ? null : e.value);
    }

    /**
     * Removes and returns the entry associated with the specified key
     * in the HashMap.  Returns null if the HashMap contains no mapping
     * for this key.
     */
    final Entry<K,V> removeEntryForKey(Object key) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                modCount++;
                size--;
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }
 private abstract class HashIterator<E> implements Iterator<E> :这个里面
 final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)  如果刚刚执行了map.remove(key),那么modcount就变了,导致iterator再进行判断的时候两个值不一样,抛出这个异常。
                throw new ConcurrentModificationException();
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();

            if ((next = e.next) == null) {
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
           current = e;
            return e;
        }
那么执行it.remove呢:
public void remove() {
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount; //会执行这步,让两个值同步一下,就不会抛那个异常
        }

TAG:

 

评分:0

我来说两句

Open Toolbar