先定义测试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()){
用iterator迭代基本都能删除,但是用list.remove()删除的话会报ConcurrentModificationException异常,可以debug进去看下异常:String t = it.next(); if(t.equals("c")){ //list.remove(t);//用list移除会报ConcurrentModificationException异常 it.remove(); } } return list; }
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进行同步;
参考:http://www.jianshu.com/p/02a08c6c21ed
2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。
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; }