天天看點

java.util.ConcurrentModificationException 解決辦法 (轉載)

今天在項目的中有一個需求,需要在一個Set類型的集合中删除滿足條件的對象,這時想當然地想到直接調用Set的remove(Object o)方法将指定的對象删除即可,測試代碼:

public class Test {

public static void main(String[] args) {

User user1 = new User();

user1.setId(1);

user1.setName("zhangsan");

User user2 = new User();

user2.setId(2);

user2.setName("lisi");

Set userSet = new HashSet();

userSet.add(user1);

userSet.add(user2);

for (Iterator it = userSet.iterator(); it.hasNext();) {

User user = (User) it.next();

if (user.getId() == 1) {

userSet.remove(user);

}

if (user.getId() == 2) {

user.setName("zhangsan");

}

}

for(Iterator it = userSet.iterator(); it.hasNext(); ) {

User user = (User) it.next();

System.out.println(user.getId() + "=>" + user.getName());

}

}

}

但運作程式的時候,卻發現出錯了:

Exception in thread "main" java.util.ConcurrentModificationException

at java.util.HashMap$HashIterator.nextEntry(Unknown Source)

at java.util.HashMap$KeyIterator.next(Unknown Source)

at test.Test.main(Test.java:23)

從API中可以看到List等Collection的實作并沒有同步化,如果在多 線程應用程式中出現同時通路,而且出現修改操作的時候都要求外部操作同步化;調用Iterator操作獲得的Iterator對象在多線程修改Set的時 候也自動失效,并抛出java.util.ConcurrentModificationException。這種實作機制是fail-fast,對外部 的修改并不能提供任何保證。

網上查找的關于Iterator的工作機制。Iterator是工作在一個獨立的線程中,并且擁有一個 mutex鎖,就是說Iterator在工作的時候,是不允許被疊代的對象被改變的。Iterator被建立的時候,建立了一個記憶體索引表(單連結清單),這 個索引表指向原來的對象,當原來的對象數量改變的時候,這個索引表的内容沒有同步改變,是以當索引指針往下移動的時候,便找不到要疊代的對象,于是産生錯 誤。List、Set等是動态的,可變對象數量的資料結構,但是Iterator則是單向不可變,隻能順序讀取,不能逆序操作的資料結構,當 Iterator指向的原始資料發生變化時,Iterator自己就迷失了方向。

如何才能滿足需求呢,需要再定義一個List,用來儲存需要删除的對象:

List delList = new ArrayList();

最後隻需要調用集合的removeAll(Collection con)方法就可以了。

public class Test {

public static void main(String[] args) {

boolean flag = false;

User user1 = new User();

user1.setId(1);

user1.setName("shangsan");

User user2 = new User();

user2.setId(2);

user2.setName("lisi");

Set userSet = new HashSet();

userSet.add(user1);

userSet.add(user2);

List delList = new ArrayList();

for (Iterator it = userSet.iterator(); it.hasNext();) {

User user = (User) it.next();

if (user.getId() == 1) {

delList.add(user);

}

if (user.getId() == 2) {

user.setName("zhangsan");

}

}

userSet.removeAll(delList);

for(Iterator it = userSet.iterator(); it.hasNext(); ) {

User user = (User) it.next();

System.out.println(user.getId() + "=>" + user.getName());

}

}

}

繼續閱讀