錯(cuò)誤堆棧如下
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922)
at java.util.HashMap$KeyIterator.next(HashMap.java:956)
...
hashMap的相關(guān)實(shí)現(xiàn)源碼如下:
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時(shí)并且map的size被修改過(guò)了,導(dǎo)致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進(jìn)行線程安全的復(fù)制。
hashMap = ...
copyUserMap = ImmutableMap.copyOf(hashMap);
Iterator<String> keys = copyUserMap.keySet().iterator();
while (keys.hasNext()) {
...
}
由于HashMap是線程不安全的,這樣在遍歷的時(shí)候不會(huì)因?yàn)槎嗑€程的修改map而導(dǎo)致并發(fā)異常。除了該方法,還可以使用concurrentHashMap,獲取線程鎖解決。