因为大家都知道ArrayList,LinkedList没有使用synchronized对线程同步作任何处理,也就是说它们在同一时刻可以由多个线程访问,不是线程安全的,所以在移除的过程中会产生莫名奇妙的错误;而Vector,Stack则使用synchronized对主要方法作了同步控制,它们在同一时刻只能由一个线程访问,所以这里没有什么可说的。
我首先使用for each 语句进行删除。
public static void testList(){
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("test");
for(String str : list){
list.remove(str);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at net.greatsoft.Test.testList(Test.java:36)
at net.greatsoft.Test.main(Test.java:24) 这段代码居然抛出了异常
java.util.ConcurrentModificationException。
查看JDK6手册
public class ConcurrentModificationException
extends
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法 是:ConcurrentModificationException 应该仅用于检测 bug。
Java中的For each实际上使用的是iterator进行处理的。而iterator是不允许集合在iterator使用期间删除的。而我在for each时,从集合中删除了一个元素,这导致了iterator抛出了ConcurrentModificationException。
方法一:用传统for循环,从集合最后元素向前循环删除元素,集合的size会变小,连带索引都会改变,但不会影响到前面的未循环元素。
ArrayList<Integer> a=new ArrayList<Integer>(15);
a.add(222);
a.add(3);
a.add(333);
a.add(000);
a.add(333);
a.add(4);
for(int i=0; i<a.size();i++) {
a.remove(i); //这里防止有遗漏Item,正确做法让指针向前移动 i--;
}
}
方法二:使用Iterator的remove()方法删除集合中的元素
查看JDK手册的Iterator接口,看到它还有一个remove方法。
remove
void remove()
从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的 collection,则迭代器的行为是不确定的。
Iterator<String> it = list.iterator();
//这种方式也是在同一线程是安全的
while(it.hasNext()) {
it.next();
it.remove();
}
如果防止多线程之间可以安全的访问必须在方法前synchronized关键字以保证线程能够同步
感谢iteye网友博客,看到网友写的Code Demo很是复杂麻烦,我从新整理一下,仅供大家参考~~~