1.产生情景
在做项目中遇到如下需求:遍历集合,删除其中值=2的元素。代码如下:
@Test
public void test()
{
List<Integer> list = new ArrayList<Integer>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for (Integer integer : list)
{
if (integer==2)
{
list.remove(2);
}
}
}
运行后抛出如下异常:
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at com.mycompany.app.ConcurrentModifyTest.test(ConcurrentModifyTest.java:22)
2.产生原因
ArrayList等的Collection的实现并没有同步化(也就是没有synchronized),如果在多线程应用中出现同时访问和修改时,要求外部操作必须要同步,如果不是同步就会抛出这个异常。
简单地说就是:不能在遍历的时候通过list、map等容器本身删除其中的元素
3.单线程的解决方案
既然不能通过容器来删除,那么就使用迭代器本身的remove方法来删除即可
@Test
public void test()
{
List<Integer> list = new ArrayList<Integer>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext())
{
Integer i = iterator.next();
if (i==2)
{
iterator.remove();
}
}
}
4.多线程的解决方案
单线程的解决方案在多线程情况下就不适用了,而且就算是将ArrayList换为同步容器Vector也还是会出现这种问题。
解决方案有以下两种:
(1)使用并发容器(推荐)
如CopyOnWriteArrayList代替ArrayList和Vector,用ConcurrentHashMap代替HashMap
(2)通过synchronized或者Lock将iterator操作放入其中