简单的小代码贴上:
public class ConcurrentModificationExceptionExample {
public static void main(String[] args) {
Collection<User> users = new ArrayList<>();
users.add(new User("张三", 28));
users.add(new User("李四", 25));
users.add(new User("王五", 31));
Iterator itrUsers = users.iterator();
while (itrUsers.hasNext()) {
User user = (User) itrUsers.next();
if ("李四".equals(user.getName())) {
users.remove(user);
} else {
System.out.println(user);
}
}
}
}
class User{
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
最后的执行结果有点诡异:
当要remove集合中的元素是name为'张三'的时候:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at studythread.ConcurrentModificationExceptionExample.main(ConcurrentModificationExceptionExample.java:23)
当要remove集合中的元素是name为'李四'的时候:
User [name=张三, age=28]
当要remove集合中的元素是name为'王五'的时候:
User [name=张三, age=28]
User [name=李四, age=25]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at studythread.ConcurrentModificationExceptionExample.main(ConcurrentModificationExceptionExample.java:34)
总是在碰到这个问题才想起!
记得还是看张孝祥老师的java多线程与并发库视频教程才大概明白原因!
!!!是否还记得在学习List集合的时候,有说过,
在迭代的过程中不要使用集合操作容易出现异常,
JDK5之后提出了很多线程安全的容器, 与前辈synchronized方式比起来, 它们的亮点并不是保证了线程安全, 而是它们在保证线程安全的同时尽量避免并发瓶颈基本上限制条件多的容器都能实现Concurrent版本, 保持一定的读写并发; 像ArrayList LinkedList很难避开并发瓶颈, 退而求其次ArrayList实现了CopyOn保证了读并发;
LinkedList只能是通过Collections.synchronizedList()的synchronized方式(读|读都有锁), 尽量用其他集合替代.
解决方式1:Collection users = new CopyOnWriteArrayList();
至于原因:可以查看AbstractList这个类的源码,
在你调用迭代器的next()方法时,它的实现类中会调用checkForComodification()方法,
if (modCount != expectedModCount)
就是判断修改的次数和预期修改次数是否一致,若不一致就会抛出异常。
就是说在这个集合中,你对这个集合进行删除,添加,在迭代器的实现类中有个属性来记录你操作的次数。
当获取迭代器的时候modCount应该是3(进行了三次add),
那么当你获取迭代器,其实=实现类内部一实例化的时候就会将modCount赋值给expectedModCount,
再remove()的时候modCount就是4了,remove完了之后再去next(),一检查,
不一致,那么就报错喽。
当要移除的是李四的时候,调用hasNext()方法,
返回的就是:cursor != size();的值
其中cursor变量,记录的是操作下元素的角标,size()就是这个集合的大小,
当你进行remove的时候这个集合的大小已经是2了,在上一次next()的时候cursor已经是2了,
so?2!=2,返回的肯定是false,while循环结束,就没有进到这个next()方法中去,就没抛出异常。
当要移除的是王五时,cursor的值已经是3了,remove()方法之后size()的值是2,调用hashNext()的时候,返回true,
当获取迭代器的时候modCount是3(进行了三次add),内部将expectedModCount=modCount,
remove()方法执行之后modCount就是为4了,执行到next()的时候,内部调用checkForComodification,
if (modCount != expectedModCount)throw new ConcurrentModificationException();
3!=4,抛出异常!。
方式2:List集合有个方法:list.listIterator();
返回的是一个ListIterator,它是Iterator的子接口,
通过这个对象可以实现对List集合的迭代,同时可对集合进行元素的增删改。
只适用于List集合。 只适用于List集合。 只适用于List集合。
如有不对之处或者你们有更好的解决方式,希望能够告知。感谢!