Java中容器的迭代器的fail-fast機制

Iterator<Integer> keys = gradeMap.keySet().iterator();
        while(keys.hasNext()){
            Integer i = keys.next();
            if(!gradesIds.contains(i)){
//                keys.remove(); 
                gradeMap.remove(i);
            }
        }java

調用HashMap的reomve方法時會出現 java.util.ConcurrentModificationException 。網絡

解決方法就是先用Iterator的方法remove,而後再調用HashMap的remove方法!!即代碼以下:併發

Iterator<Integer> keys = gradeMap.keySet().iterator();
        while(keys.hasNext()){
            Integer i = keys.next();
            if(!gradesIds.contains(i)){
                keys.remove(); 
                gradeMap.remove(i);
            }
        }this

產生此問題的緣由spa

引用於網絡:
       當使用 fail-fast iterator 對 Collection 或 Map 進行迭代操做過程當中嘗試直接修改 Collection / Map 的內容時,即便是在單線程下運行, java.util.ConcurrentModificationException 異常也將被拋出。 

Iterator 是工做在一個獨立的線程中,而且擁有一個 mutex 鎖。 Iterator 被建立以後會創建一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,因此當索引指針日後移動的時候就找不到要迭 代的對象,因此按照 fail-fast 原則 Iterator 會立刻拋出 java.util.ConcurrentModificationException 異常。 

因此 Iterator 在工做的時候是不容許被迭代的對象被改變的。但你可使用 Iterator 自己的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。 

有意思的是若是你的 Collection / Map 對象實際只有一個元素的時候, ConcurrentModificationException 異常並不會被拋出。這也就是爲何在 javadoc 裏面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs. 

附:來自ibm developerworks上對java.util.concurrent包的說明片斷: 
      java.util 包中的集合類都返回 fail-fast 迭代器,這意味着它們假設線程在集合內容中進行迭代時,集合不會更改它的內容。若是 fail-fast 迭代器檢測到在迭代過程當中進行了更改操做,那麼它會拋出 ConcurrentModificationException ,這是不可控異常。 
      在迭代過程當中不更改集合的要求一般會對許多併發應用程序形成不便。相反,比較好的是它容許併發修改並確保迭代器只要進行合理操做,就能夠提供集合的一致視圖,如 java.util.concurrent 集合類中的迭代器所作的那樣。 
     java.util.concurrent 集合返回的迭代器稱爲弱一致的(weakly consistent) 迭代器。對於這些類,若是元素自從迭代開始已經刪除,且還沒有由 next() 方法返回,那麼它將不返回到調用者。若是元素自迭代開始已經添加,那麼它可能返回調用者,也可能不返回。在一次迭代中,不管如何更改底層集合,元素不會被 返回兩次。線程

相關文章
相關標籤/搜索