异常: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();

至于原因:可以查看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集合。


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



猜你喜欢

转载自blog.csdn.net/fellhair/article/details/80874177
今日推荐