迭代器的 ConcurrentModificationException
迭代器的 ConcurrentModificationException
在使用迭代器遍歷 HashMap, ArrayList時碰到了這個異常,
碰到異常莫得慌,仔細分析,不難發現,出現異常的語句是: map.remove(key)。
解決方案:如果程式要求是執行緒安全的, 那麼可以使用安全的集合 (ConcurrentHashMap), 但如果說只是簡單的實現遍歷, 可以使用迭代器的刪除方法 : its.remove() 刪除當前元素
那麼為什麼會出現該異常呢??
我們都知道 HashMap, ArrrayList 都是執行緒不安全的,
HashMap的成員屬性 modCount : 表示修改結構的次數,當一個執行緒讀, 一個執行緒寫時,modCount與期望值不相同,就會觸發快速失敗,立即報告錯誤, 丟擲異常。
具體分析:HashMap中:
KeyIterator類 繼承了 HashIterator 類, 檢視 HashIterator 類
Node<K,V> next; // 下一個entry的位置
Node<K,V> current; // 當前 entry
int expectedModCount; // 期望值, 若不滿足,觸發快速失敗
int index; // 當前位置
遍歷時會判斷 當前 modCount 與 期望值是否相同,
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount) //判斷 當前 modCount 與 期望值是否相同,
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key, e.value);
}
if (modCount != mc) //判斷 當前 modCount 與 期望值是否相同,
throw new ConcurrentModificationException();
}
}
HashMap中的 remove 方法, 會直接修改modCount的值, 導致與期望值不同,丟擲異常, 那麼 迭代器的 remove方法為什麼不會丟擲異常呢?
這是因為 該方法在更新 modCount時,同步更新了 期望值
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount; //同步更新期望值
}
繼續看ArrayList,
ArrayList中的remove方法,都會修改了 modCount
public E remove(int index) {
rangeCheck(index);
modCount++; 修改了modCount
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
一樣的邏輯,ArrayList中 Itr類中的next 方法,會檢查modCount是否一致,
int cursor; // 要返回的下一個元素的索引
int lastRet = -1; // 返回最後一個元素的索引;如果沒有返回,則返回-1
int expectedModCount = modCount; //期望值
檢視: checkForComodification方法
final void checkForComodification() {
if (modCount != expectedModCount) // 判斷
throw new ConcurrentModificationException();
}
}
Itr類中的remove方法, 會同步更新 期望值, 避免快速失敗
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; //更新期望值
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
相關文章
- Python可迭代的物件與迭代器Python物件
- 如何避免ConcurrentModificationExceptionException
- 迭代器
- Java·ConcurrentModificationException的具體原因JavaException
- python中的迭代器Python
- Python進階:迭代器與迭代器切片Python
- 不用for迭代 --手工訪問迭代器中的元素.
- java.util.ConcurrentModificationExceptionJavaException
- TypeScript迭代器TypeScript
- Python 迭代器Python
- Iterator迭代器
- 迭代器 iterator
- Lua迭代器
- Python迭代器Python
- Ruby迭代器
- 迭代器模式模式
- 從迭代器模式到迭代協議模式協議
- 可迭代物件、迭代器、生成器物件
- Iterator與Iterable(迭代器與可迭代)
- 你知道JavaScript中的可迭代物件與迭代器嗎JavaScript物件
- STL中的迭代器分類
- Python——迭代器的高階用法Python
- Python中迭代器的實現Python
- 搞清楚 Python 的迭代器、可迭代物件、生成器Python物件
- Iterables和迭代器
- 迭代器模式(Iterator)模式
- 23. 迭代器
- 迭代器總結
- javascript 之迭代器JavaScript
- 手寫自定義迭代器,秒懂迭代器底層原理
- 迭代器與可迭代物件的區別,以及iter()函式的使用。物件函式
- Python之可迭代物件、迭代器、生成器Python物件
- ConcurrentModificationException併發修改異常Exception
- PHP的迭代器和生成器PHP
- List分組迭代器
- 迭代器、生成器
- 協程與迭代器
- 迭代器,生成器