Java并发编程7-循环删除集合元素
2017-02-22 00:00
246 查看
1 异常情况举例
先来看看都有哪些情况会出现ConcurrentModificationException异常,下面以ArrayList remove 操作进行举例。使用的数据集合:
List<string> myList = new ArrayList<string>(); myList.add( "1"); myList.add( "2"); myList.add( "3"); myList.add( "4"); myList.add( "5");
以下三种情况都会出现异常:
Iterator<string> it = myList.iterator(); while (it.hasNext()) { String value = it.next(); if (value.equals( "3")) { myList.remove(value); // error } } for (Iterator<string> it = myList.iterator(); it.hasNext();) { String value = it.next(); if (value.equals( "3")) { myList.remove(value); // error } } for (String value : myList) { System. out.println( "List Value:" + value); if (value.equals( "3")) { myList.remove(value); // error } }
异常信息如下:
2 根本原因
以上都有3种出现异常的情况有一个共同的特点,都是使用Iterator进行遍历,且都是通过ArrayList.remove(Object) 进行删除操作。想要找出根本原因,直接查看ArrayList源码看为什么出现异常:public class ArrayList<e> extends AbstractList<e> implements Cloneable, Serializable, RandomAccess { @Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null) { for (int i = 0; i < s; i++) { if (object.equals(a[i])) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 只要删除成功都是累加 return true; } } } else { for (int i = 0; i < s; i++) { if (a[i] == null) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 只要删除成功都是累加 return true; } } } return false; } @Override public Iterator<e> iterator() { return new ArrayListIterator(); } private class ArrayListIterator implements Iterator<e> { ...... // 全局修改总数保存到当前类中 /** The expected modCount value */ private int expectedModCount = modCount; @SuppressWarnings("unchecked") public E next() { ArrayList<e> ourList = ArrayList.this; int rem = remaining; // 如果创建时的值不相同,抛出异常 if (ourList.modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (rem == 0) { throw new NoSuchElementException(); } remaining = rem - 1; return (E) ourList.array[removalIndex = ourList.size - rem]; } ...... } }
List、Set、Map 都可以通过Iterator进行遍历,这里仅仅是通过List举例,在使用其他集合遍历时进行增删操作都需要留意是否会触发ConcurrentModificationException异常。
3 单线程解决方案
// 1 使用Iterator提供的remove方法,用于删除当前元素 for (Iterator<string> it = myList.iterator(); it.hasNext();) { String value = it.next(); if (value.equals("3")) { it.remove(); // ok } } System.out.println("List Value:" + myList.toString()); // 2 建一个集合,记录需要删除的元素,之后统一删除 List<string> templist = new ArrayList<string>(); for (String value : myList) { if (value.equals("3")) { templist.add(value); } } // 可以查看removeAll源码,其中使用Iterator进行遍历 myList.removeAll(templist); System.out.println("List Value:" + myList.toString()); // 3. 使用线程安全CopyOnWriteArrayList进行删除操作 List<string> myList = new CopyOnWriteArrayList<string>(); myList.add("1"); myList.add("2"); myList.add("3"); myList.add("4"); myList.add("5"); Iterator<string> it = myList.iterator(); while (it.hasNext()) { String value = it.next(); if (value.equals("3")) { myList.remove("4"); myList.add("6"); myList.add("7"); } } System.out.println("List Value:" + myList.toString()); // 4. 不使用Iterator进行遍历,需要注意的是自己保证索引正常 for (int i = 0; i < myList.size(); i++) { String value = myList.get(i); System.out.println("List Value:" + value); if (value.equals("3")) { myList.remove(value); // ok i--; // 因为位置发生改变,所以必须修改i的位置 } } System.out.println("List Value:" + myList.toString());
4 多线程解决方案
使用ConcurrentHashMap或者CopyOnWriteArrayList,代码示例如下package com.niuniu.study.spring; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class Test1 { public static void main(String[] args) { final List<String> myList = new CopyOnWriteArrayList<String>(); for (int i = 1; i <= 5; i++) { myList.add(i + ""); } new Thread(new Runnable() { @Override public void run() { for (String string : myList) { System.out.println("遍历集合 value = " + string); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < myList.size(); i++) { String value = myList.get(i); if (Integer.parseInt(value) % 2 == 0) { myList.remove(value); System.out.println("删除元素: " + value); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
结果如下:
遍历集合 value = 1
删除元素: 2
删除元素: 4
遍历集合 value = 2
遍历集合 value = 3
遍历集合 value = 4
遍历集合 value = 5
相关文章推荐
- Java中如何循环删除一个集合(如List)中的多个元素
- foreach循环删除集合中的元素出现ConcurrentModificationException异常(补充)
- 在循环中删除集合的元素
- 删除正在循环迭代的集合元素的分析
- 关于循环删除集合中的元素
- Java中如何循环删除一个集合(如List)中的多个元素
- 循环的时候如何安全地删除java集合的元素
- java中如何在循环中准确删除集合中的某个元素,并且不引起错误
- foreach循环删除集合中的元素出现ConcurrentModificationException异常
- Java中如何循环删除一个集合(如List)中的多个元素
- C#循环删除集合中的元素
- java中循环遍历删除List和Set集合中元素的方法
- Java中如何循环删除一个集合(如List)中的多个元素
- 实现不用循环,删除集合中的重复(任意)元素
- java中循环遍历删除List和Set集合中元素的方法
- java循环中如何删除集合中的元素
- 循环删除list集合元素
- java集合循环中删除元素问题以List集合为例
- java中循环遍历删除List和Set集合中元素的方法(推荐)