异常:java.util.ConcurrentModificationException

简单的小代码贴上:

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();
  2. List集合有个方法:list.listIterator(); 返回的是一个ListIterator,它是Iterator的子接口,通过这个对象可以实现对List集合的迭代,同时可对集合进行元素的增删改。只适用于List集合。只适用于List集合。只适用于List集合。
  3. 用迭代器来操作当前的元素,而不是用集合对象来操作

至于出现上面输出的原因:可以查看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,抛出异常!。

如有不对之处或者你们有更好的解决方式,希望能够告知。感谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值