java.util.ConcurrentModificationException 時的解決辦

醉面韋陀發表於2009-05-05

在對一個map進行迭代遍歷並刪除一些符合條件的鍵值對的時候,容易出現

     java.util.ConcurrentModificationException 這個異常。
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
 at java.util.HashMap$KeyIterator.next(HashMap.java:823)

解決辦法如下:

import java.util.*;

public class TestMap {
  public TestMap() {
  }

  public static void main(String[] args) {
    java.util.Map m = new java.util.HashMap();
    m.put("aaa", "lizongbo ");
    m.put("bbb", " lizongbo");
    m.put("ccc", "lizongbo  ");
    m.put("ddd", "  lizongbo");
    m.put("eee", "lizongbo");
    m.put("fff", "lizongbo");
    m.put("ggg", "lizongbo");
    m.put("adads", "lizongbo");
    m.put("dffd", "lizongbo");
    m.put("dcxv", "lizongbo");
    m.put("lizongbo", "lizongbo");
    m.put("ert", "lizongbo");
    m.put("544", "lizongbo ");
    Iterator iterator = m.keySet().iterator();
    while (iterator.hasNext()) {
      String sessionId = (String) iterator.next();
      if ("ggg".equals(sessionId) || "lizongbo".equals(sessionId) ||
          "544".equals(sessionId)) {
        iterator.remove();       //這行程式碼是關鍵。
        m.remove(sessionId);
      }
    }
    System.out.println(m.get("ggg"));
    System.out.println(m.get("lizongbo"));
    System.out.println(m.get("544"));
  }

原因: jdk5.0以上的for-each也是利用內部的iterator來遍歷集合的(跟以前的iterator一樣)獲得的Iterator是一個內部類產生的迭代器,這個迭代器在呼叫next方法時,會檢查列表是否被修改過,如果被修改過,就會丟擲ConcurrentModificationException異常。進一步說,當使用 fail-fast iterator 對 Collection 或 Map 進行迭代操作過程中嘗試直接修改 Collection / Map 的內容時,即使是在單執行緒下運xi,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.

解決方法:在Map或者Collection的時候,不要用它們的API直接修改集合的內容,如果要修改可以用Iterator的remove()方法

由於for-each的寫法,使我們無法獲得iterator物件,所以這種遍歷方式不能進行刪除操作。只好改成了比較土的方法實現了,如下:

            for (Iterator it = desk.getPkers().iterator(); it.hasNext();) {                 

                   PKer pkerOnDesk =(PKer) it.next();  

                   it.remove();

            }

 

相關文章