一,示例代码:
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
Iterator it = list.iterate();
while(it.hasNext()) {
Object obj = it.next();
list.remove(1);
}
此时绝逼会抛java.util.ConcurrentModificationException错误,怎么会呢,仔细查看JDK,原来如此
注意,此实现不是同步的。如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:List list = Collections.synchronizedList(new ArrayList(...));
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
二,解决办法:
- // 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.remove(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());
这里有很棒得一个总结