删除ArrayList时的Java ConcurrentModificationException

删除ArrayList时的Java ConcurrentModificationException,java,concurrency,Java,Concurrency,当ArrayList的大小为2时,我们使用foreach循环执行删除操作,它打印最后一个元素,不会引发异常 例如: ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz")); for(String i : a){ a.remove(i); } // a contains "xyz" arraylista=新的ArrayList(Arrays.asList(

当ArrayList的大小为2时,我们使用foreach循环执行删除操作,它打印最后一个元素,不会引发异常

例如:

ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
    for(String i : a){
        a.remove(i);
    }
// a contains "xyz"
arraylista=新的ArrayList(Arrays.asList(“abc”、“xyz”);
用于(字符串i:a){
a、 删除(i);
}
//a包含“xyz”
但是当我们将arrayList的大小增加到2以上,并执行该操作时,它会显示concurrentModificationException。
为什么它会显示这样的行为(它适用于2个元素,但不能超过2个)?

这是实现的一个怪癖

该异常仅在尽力而为的基础上抛出,不能保证它会被抛出

要了解原因,您需要了解增强for循环的设计方式:

for (String i : a) {
  a.remove(i);
}
被编译为类似于:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
  String i = a.next();
  a.remove(i);
}
int idx = 0;

boolean hasNext() {
  return idx < a.size();
}

Object next() {
  checkForModification(); // throws exception if list has been modified.
  return a.get(idx++);
}
Iterator it=a.Iterator();
while(it.hasNext()){
字符串i=a.next();
a、 删除(i);
}
接下来,迭代器的实现方式如下:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
  String i = a.next();
  a.remove(i);
}
int idx = 0;

boolean hasNext() {
  return idx < a.size();
}

Object next() {
  checkForModification(); // throws exception if list has been modified.
  return a.get(idx++);
}
intidx=0;
布尔hasNext(){
返回idx
因此,如果列表最初的大小为2,则循环的执行如下:

  • 检查
    hasNext()
    idx==0
    ,并且
    0<2
    为true,因此返回true
  • 调用
    next()
    :检索
    i=a.get(0)
    ,递增
    idx
    ,因此
    idx==1
  • a
    中删除
    i
    。现在
    a.size()==1
循环执行了一次。现在它再次执行:

  • 检查
    hasNext()
    idx==1
    ,并且
    1<1
    为false,因此返回false
因此执行停止,没有
ConcurrentModificationException
。列表仍然包含初始的第二项


如果列表最初大于2,循环将再次执行(因为
idx==1
,并且
size()==initial size()-1
,所以
idx
),所以
next()
将在
remove()
之后再次调用。列表已被修改,因此
checkForModification()
引发异常。

这是实现的一个怪癖

该异常仅在尽力而为的基础上抛出,不能保证它会被抛出

要了解原因,您需要了解增强for循环的设计方式:

for (String i : a) {
  a.remove(i);
}
被编译为类似于:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
  String i = a.next();
  a.remove(i);
}
int idx = 0;

boolean hasNext() {
  return idx < a.size();
}

Object next() {
  checkForModification(); // throws exception if list has been modified.
  return a.get(idx++);
}
Iterator it=a.Iterator();
while(it.hasNext()){
字符串i=a.next();
a、 删除(i);
}
接下来,迭代器的实现方式如下:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
  String i = a.next();
  a.remove(i);
}
int idx = 0;

boolean hasNext() {
  return idx < a.size();
}

Object next() {
  checkForModification(); // throws exception if list has been modified.
  return a.get(idx++);
}
intidx=0;
布尔hasNext(){
返回idx
因此,如果列表最初的大小为2,则循环的执行如下:

  • 检查
    hasNext()
    idx==0
    ,并且
    0<2
    为true,因此返回true
  • 调用
    next()
    :检索
    i=a.get(0)
    ,递增
    idx
    ,因此
    idx==1
  • a
    中删除
    i
    。现在
    a.size()==1
循环执行了一次。现在它再次执行:

  • 检查
    hasNext()
    idx==1
    ,并且
    1<1
    为false,因此返回false
因此执行停止,没有
ConcurrentModificationException
。列表仍然包含初始的第二项


如果列表最初大于2,循环将再次执行(因为
idx==1
,并且
size()==initial size()-1
,所以
idx
),所以
next()
将在
remove()
之后再次调用。列表已被修改,因此
checkForModification()
引发异常。

在迭代列表时不能从列表中删除项目。改用迭代器。 看那边:


迭代列表时,无法从列表中删除项目。改用迭代器。 看那边:


ArrayList不是线程安全的,当您更改它的结构并进行迭代时,可能会遇到这种类型的问题

在对集合进行迭代时,需要使用迭代器安全地从集合中删除

ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
for (Iterator<String> iterator = a.iterator(); iterator.hasNext();) {
    String string = iterator.next(); // pick one element

    // do some stuffs with the content

    iterator.remove(); // remove element
}
arraylista=新的ArrayList(Arrays.asList(“abc”、“xyz”);
for(Iterator Iterator=a.Iterator();Iterator.hasNext();){
String String=iterator.next();//选择一个元素
//对内容做一些处理
迭代器.remove();//删除元素
}

ArrayList不是线程安全的,当您更改它的结构并进行迭代时,可能会遇到此类问题

在对集合进行迭代时,需要使用迭代器安全地从集合中删除

ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
for (Iterator<String> iterator = a.iterator(); iterator.hasNext();) {
    String string = iterator.next(); // pick one element

    // do some stuffs with the content

    iterator.remove(); // remove element
}
arraylista=新的ArrayList(Arrays.asList(“abc”、“xyz”);
for(Iterator Iterator=a.Iterator();Iterator.hasNext();){
String String=iterator.next();//选择一个元素
//对内容做一些处理
迭代器.remove();//删除元素
}

您看到这个了吗?你看到这个了吗?在这种情况下,迭代和修改发生在同一个线程上——这与线程安全无关。此外,这并不能真正回答OP的问题,即为什么在2个元素之后抛出异常。@Vasan“当您更改它的结构并进行迭代时,您可能会遇到这种类型的问题”。此外,他并没有真正问为什么它发生在2个或更多的元素上。他问自己是否有异常行为(简短的回答是否)。在这种情况下,迭代和修改发生在同一个线程上——这与线程安全无关。此外,这并不能真正回答OP的问题,即为什么在2个元素之后抛出异常。@Vasan“当您