I've got a ConcurrentModificationException
when operating a HashMap
. The code is as following:
Iterator<Integer> iterator =cacheMap.keySet().iterator();
while(iterator.hasNext()) {
if(iterator.next() == target) {
iterator.remove();
}
}
The only operations I used were remove like that and cacheMap.put(node)
. And the methods were all called in the main thread, including onCreate()
method of Activity
, onPostExecute()
method of AsyncTask
and handleMessage(Message msg)
method in the handler of main thread.
But occasionally, ConcurrentModificationException
was thrown in iterator.next()
when I use the method above to remove a node, although it's really few.
I've reviewed the relevant method in HashMap. It's like this:
@Override public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null) ? ks : (keySet = new KeySet());
}
private final class KeyIterator extends HashIterator
implements Iterator<K> {
public K next() { return nextEntry().key; }
}
private abstract class HashIterator {
int nextIndex;
HashMapEntry<K, V> nextEntry = entryForNullKey;
HashMapEntry<K, V> lastEntryReturned;
int expectedModCount = modCount;
HashIterator() {
if (nextEntry == null) {
HashMapEntry<K, V>[] tab = table;
HashMapEntry<K, V> next = null;
while (next == null && nextIndex < tab.length) {
next = tab[nextIndex++];
}
nextEntry = next;
}
}
public boolean hasNext() {
return nextEntry != null;
}
HashMapEntry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (nextEntry == null)
throw new NoSuchElementException();
HashMapEntry<K, V> entryToReturn = nextEntry;
HashMapEntry<K, V>[] tab = table;
HashMapEntry<K, V> next = entryToReturn.next;
while (next == null && nextIndex < tab.length) {
next = tab[nextIndex++];
}
nextEntry = next;
return lastEntryReturned = entryToReturn;
}
public void remove() {
if (lastEntryReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
HashMap.this.remove(lastEntryReturned.key);
lastEntryReturned = null;
expectedModCount = modCount;
}
}
@Override public V remove(Object key) {
if (key == null) {
return removeNullKey();
}
int hash = secondaryHash(key);
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;
}
/**
* Subclass overrides this method to unlink entry.
*/
void postRemove(HashMapEntry<K, V> e) { }
The modCount
and the expectedModeCount
is checked when calling nextEntry()
and remove
. But it seems impossible for the difference of the two integer if iterator.remove()
is called to remove node.
Just use cacheMap.remove(target).
From the Docs:
public V remove(Object key) Removes the mapping for the specified key from this map if present.
And remember a HashMap can only store one object for a given key, so no need to iterate over all values.
you can not iterate a collection and remove items from it.
use:
Set<Integer> set = new HashSet<Integer>();
Iterator<Integer> iterator =cacheMap.keySet().iterator();
while(iterator.hasNext()) {
Integer key = iterator.next();
if(key == target) {
set.add(key );
}
}
cacheMap.rmoveAll(set);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.