关于HashMap的Concurrentmodificationexception

错误堆栈如下

java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922)
        at java.util.HashMap$KeyIterator.next(HashMap.java:956)
        ...

hashMap的相关实现源码如下:

final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                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;
        }

        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;
        }

显然,工程中使用了迭代器遍历hashMap时并且map的size被修改过了,导致modCount != expectedModCount,原因是hash迭代器在将modCount赋值给expectedModCount后,modCount的值被其它线程修改掉了。

  private abstract class HashIterator<E> implements Iterator<E> {
        Entry<K,V> next;        // next entry to return
        int expectedModCount;   // For fast-fail
        int index;              // current slot
        Entry<K,V> current;     // current entry

        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }

解决方法:使用ImmutableMap进行线程安全的复制。

 hashMap = ...
 copyUserMap = ImmutableMap.copyOf(hashMap);
 Iterator<String> keys = copyUserMap.keySet().iterator();
 while (keys.hasNext()) {
               ...
 }

由于HashMap是线程不安全的,这样在遍历的时候不会因为多线程的修改map而导致并发异常。除了该方法,还可以使用concurrentHashMap,获取线程锁解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容