List删除元素报Exception in thread "main" java.util.ConcurrentModificationException异常,或数据删除不完整

来源:互联网 发布:骰子软件 编辑:程序博客网 时间:2024/06/05 16:54

先定义测试list

public static List<String> list = new ArrayList<String>();static{list.add("a");list.add("b");list.add("c");list.add("d");list.add("c");list.add("c");list.add("a");list.add("c");list.add("a");list.add("c");}

这里我主要用到三种方法:

1、Iterator迭代删除(建议使用)

public static List removeIterator(){Iterator<String> it = list.iterator();
while(it.hasNext()){
String t = it.next();if(t.equals("c")){//list.remove(t);//用list移除会报ConcurrentModificationException异常it.remove();}}return list;}
用iterator迭代基本都能删除,但是用list.remove()删除的话会报ConcurrentModificationException异常,可以debug进去看下异常:

final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }

expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
modCount :AbstractList类中的一个成员变量,list里add、remove等操作都会使modCount++。

但在多线程下时用iterator.remove()也会报ConcurrentModificationException异常,并不全在于ArrayList是非线程安全的,换成线程安全Vector也同样会报ConcurrentModificationException异常

原因在于,虽然Vector的方法采用了synchronized进行了同步,但是由于Vector是继承的AbstarctList,因此通过Iterator来访问容器的话,事实上是不需要获取锁就可以访问。那么显然,由于使用iterator对容器进行访问不需要获取锁,在多线程中就会造成当一个线程删除了元素,由于modCount是AbstarctList的成员变量,因此可能会导致在其他线程中modCount和expectedModCount值不等。

解决办法:

1)在使用iterator迭代的时候使用synchronized或者Lock进行同步;

  2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。

参考:http://www.jianshu.com/p/02a08c6c21ed





2、基本下标for循环

public static List removeFor(){for(int i=0;i<list.size();i++){if("c".equals(list.get(i))){//删除为c的元素list.remove(i);
System.out.println(list.size());//会根据remove减少,数组元素往前移,后面的会用null填补
 }}
System.out.println(list.toString());//输出结果:[a, b, d, c, a, a]   但是还有一个c元素并没有删除
return list;
}

因为下标4和5里的元素都为c,下标为4的删了,下标为5的元素移至下标为4中,但迭代值i会一直累加,所以并不会再遍历到这个内容为c的元素中,
如果要删除的元素不相邻的话是可以实现要求的。





3、增强for循环

3.1用list.remove()后还继续循环依然会报ConcurrentModificationException异常

public static List removeForeach(){for(String s:list){if("c".equals(s)){list.remove(s);}}return list;}

3.2但是remove()后跳出循环就不会报异常
public static List removeForeach(){for(String s:list){if("c".equals(s)){list.remove(s);break;//不跳出循环,会报ConcurrentModificationException异常}}return list;}


阅读全文
0 0
原创粉丝点击