本文目录
一、错误描述
二、错误原因
三、解决方案
总结
如果使用ArrayList集合时,遍历删除可以使用Iterator迭代器遍历,不能使用for(;;){}这种foreach格式的;
如果使用CopyOnWriteArrayList集合时,遍历删除可以使用foreach遍历,不能使用Iterator迭代器进行删除;
一、错误描述
ArrayList是java开发时经常使用的一个类,又经常碰到需要对ArrayList循环删除元素的情况。这时候大家都不会使用foreach循环的方式来遍历List,因为它会抛异常。 Vector也同样会报异常。比如下面的代码:
public class ConcurrentTest {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
(new Person("张三", 23));
(new Person("李四", 24));
(new Person("王五", 25));
(new Person("麻六", 26));
(person -> {
if (() == 24){
(person);
}
});
(list);
}
}
抛出异常信息如下:
Exception in thread "main"
at (:1252)
at (:23)
二、错误原因
其实,基本上所有的集合类都会有一个叫做快速失败的校验机制,当一个集合在被多个线程修改并访问时,就会出现ConcurrentModificationException 校验机制。它的实现原理就是我们经常提到的modCount修改计数器。如果在读列表时,modCount发生变化则会抛出ConcurrentModificationException异常。这与线程同步是两码事,线程同步是为了保护集合中的数据不被脏读、脏写而设置的。
首先java的foreach循环其实就是根据list对象创建一个Iterator迭代对象,用这个迭代对象来遍历list,相当于list对象中元素的遍历托管给了Iterator,你如果要对list进行增删操作,都必须经过Iterator。iterator创建的时候modCount被赋值给了expectedModCount,但是调用list的add和remove方法的时候不会同时自动增减expectedModCount,这样就导致两个count不相等,从而抛出异常。
三、解决方案
使用CopyOnWriteArrayList<>(),例如如下例子:
public class ConcurrentTest {
public static void main(String[] args) {
List<Person> copyList = new CopyOnWriteArrayList<>();
(new Person("张三", 23));
(new Person("李四", 24));
(new Person("王五", 25));
(new Person("麻六", 26));
(person -> {
if (() == 25){
(person);
}
});
(copyList);
}
}
【参考资料】
关于ArrayList与CopyOnWriteArrayList的遍历remove操作:关于ArrayList与CopyOnWriteArrayList的遍历remove操作_copyonwritearraylist remove_LZ可是懒大王的博客-****博客