开发者

In Java how can this throw a ConcurrentModificationException in a single threaded program? [duplicate]

开发者 https://www.devze.com 2023-02-11 22:10 出处:网络
This question already has answers here: Why is a ConcurrentModificationException thrown and how to debug it
This question already has answers here: Why is a ConcurrentModificationException thrown and how to debug it (8 answers) Closed 3 years ago.

I was reading this "Freuqent Java concurrency problems" question and got confused by an answer talking about java.util.ConcurrentModificationException.

My understanding of开发者_如何学运维 the answer is that this can occur in a single-threaded program. How or what conditions cause the following code to throw the exception?

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }


This snippet will always throw a ConcurrentModificationException.

The rule is the following: You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop).

Note however that you are allowed to modify the list through the iterator (because then it is aware of the modification, and can take it into account) using the Iterator.remove or ListIterator.add.

From the docs:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.

The word concurrent here refers to that you're modifying the list during traversal.


Because you are deleting from a list and iterating on it using a iterator at the same time.

See equivalent code using iterator.

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          String a=itr.next();
           list.remove(a);
      }
   }
}

Right code is

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          itr.remove();
      }
   }
}


You are changing a list as you loop through it.

Here ConcurrentModificationException has nothing to do with threads.

Warning! The following example is here to show how it may be dangerous to use a collection as you change it. It's not what exactly happened in OP's case (looping through iterator and changing)

I think it would be easier to imagine what's wrong with it if you use an old-fashioned loop with a counter like this:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));

for (int i = 0; i < list.size(); i++) { 
   list.remove(i);  //removes element at given index
} 

Now, the first time i is 0, and 0th element is removed. The second time i is 1, so now 1st element is removed. But, what is now 1st, used to be 2nd, before the first removal. So, what used to be 1st, and now is 0th, will never be removed.

0

精彩评论

暂无评论...
验证码 换一张
取 消