Java : ConcurrentModificationException while iterating over list [duplicate] - java

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
When I execute the following code, I get ConcurrentModificationException
Collection<String> myCollection = Collections.synchronizedList(new ArrayList<String>(10));
myCollection.add("123");
myCollection.add("456");
myCollection.add("789");
for (Iterator it = myCollection.iterator(); it.hasNext();) {
String myObject = (String)it.next();
System.out.println(myObject);
myCollection.remove(myObject);
//it.remove();
}
Why am I getting the exception, even though I am using Collections.synchronizedList?
When I change myCollection to
ConcurrentLinkedQueue<String> myCollection = new ConcurrentLinkedQueue<String>();
I don't get that exception.
How is ConcurrentLinkedQueue in java.util.concurrent different from Collections.synchronizedList ?

A synchronized List will does not provide a new implementation of Iterator. It will use the implementation of the synchronized list. The implementation of iterator() is:
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
From ArrayList:
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
From ConcurrentLinkedQueue#iterator:
Returns an iterator over the elements in this queue in proper sequence. The returned iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.
The iterators returned by the two collections are different by design.

don't do
myCollection.remove(myObject);
do
it.remove();
There is no need for synchronization or concurrent collection

How is ConcurrentLinkedQueue in java.util.concurrent different from Collections.synchronizedList?
They have different implementations, and therefore may choose whether to throw ConcurrentModificationException, or to handle the situation you describe gracefully. Evidently CLQ handles gracefully, and ArrayList wrapped by Collections.synchronizedList (my guess is the behavior is ArrayList's, not the wrapper's) does not.
As #unbeli says, remove through the iterator, not the collection while iterating.

Related

Different results with Iterator for Java Framework Collection

I have some questions about the different behaviors of Iterator on the main Java Framework Collection classes (not only for the List class).
List
If I write for-each I will have an exception:
Collection<String> cc= new ArrayList<>(3);
cc.add("Cio");
cc.add("Mio");
cc.add("Tio");
for (String s:cc) {
System.out.println(s);
cc.remove(s); //Exception
}
If I use the Iterator, I will have not an exception:
for (Iterator<String> it =cc.iterator(); it.hasNext();) {
String s =it.next();
if (s.startsWith("C"))
it.remove();
}
ArrayDeque
This is different for ArrayDeque, infact if I use for-each, I will
have not an exception:
ArrayDeque<String> greetings = new ArrayDeque<String>();
greetings.push("hello");
greetings.push("hi");
greetings.push("ola");
greetings.pop();
greetings.peek();
while (greetings.peek() != null)
System.out.print(greetings.pop());
But if I use the iterator, I will have an exception:
Iterator<String> it = greetings.iterator();
while(it.hasNext()) {
System.out.println(greetings.pop()); //Exception
}
Why? And does the iterator throw an exception for the other JFC collections, in particular: HashSet, TreeSet, LinkedList?
Thanks a lot!
A.
ArrayList
The list maintains a modCount field that is incremented each time a structural modification is done to the list.
Structural modifications are those that change the size of the list,
or otherwise perturb it in such a fashion that iterations in progress
may yield incorrect results.
Further...
If the value of this field changes unexpectedly, the iterator (or list
iterator) will throw a ConcurrentModificationException in response to
the next, remove, previous, set or add operations. This provides
fail-fast behavior, rather than non-deterministic behavior in the face
of concurrent modification during iteration.Use of this field by
subclasses is optional.
If a subclass wishes to provide fail-fast iterators (and list
iterators), then it merely has to increment this field in its add(int,
E) and remove(int) methods (and any other methods that it overrides
that result in a structural modification the list.
The two peice of list iteration code :
1.
for (String s:str1) {
System.out.println(s);
str1.remove(s);
}
and
2.
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
--may seem identically but are internally a bit different.
Its worth mentioning that the iterator of the list maitains a expectedModCount. That should be in sync with modCount when modifying the list while iterating.
In 1st case, String s:str1 gets the iterator, checks hasNext() and calls the next(), just like in the 2nd case. The difference comes in remove() method call. str1.remove(s); calls the remove method of the ArrayList. This increments the modCount but not expectedModCount. So in the second iteration, when next() is called it throws ConcurrentModificationException. On the other hand, in 2nd case, i1.remove(); calls the remove method from Iterator implementation in ArrayList. This increments the the modCount and expectedModCount and -- Bingo.
Note: Missing the i1.next(); in the second scenario will cause IllegalStateExcepton. This is because the cursor for the next element in the list is not updated.
TakeAway: Dont call the list.remove(element) method while iterating the list. This method is meant to be called when not in an iteration.
ArrayDeque
If you iterate the ArrayDeque like this:
Iterator<String> i1 = str.iterator();
while(i1.hasNext()) {
i1.next();
i1.remove();
}
-- it works the exact same way as its ArrayList counterpart.
When calling pop() or push() method of the ArrayDeque class, you don't actually iterate on the queue, you just modify the head or tail of the queue. This is just like calling remove() method of the ArrayList class when not in Iteration (not the remove() of Iterator of ArrayList). This doesn't qualify to be a structural modification. So it doesn't throw an Exception.
Refer this article.

ConcurrentModificationException when deleting an element from ArrayList

Java is throwing ConcurrentModificationException when I am running the following code. Any idea why is that?
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1){
list1.remove(2);
System.out.println(s);
}
If you take a look at documentation of ConcurrentModificationException you will find that
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it
...
Note that this exception does not always indicate that an object has
been concurrently modified by a different thread. If a single thread
issues a sequence of method invocations that violates the contract of
an object, the object may throw this exception. For example, if a
thread modifies a collection directly while it is iterating over the
collection with a fail-fast iterator, the iterator will throw this
exception.
Important thing about this exception is that we can't guarantee it will always be thrown as stated in documentation
Note that fail-fast behavior cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of
unsynchronized concurrent modification. Fail-fast operations throw
ConcurrentModificationException on a best-effort basis.
Also from ArrayList documentation
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.
(emphasis mine)
So you can't manipulate content of Collection (in your case List) while iterating over it via enhanced for loop because you are not doing it via iterator for-each is using internally.
To solve it just get your own Iterator and use it in your loop. To remove elements from collection use remove like in this example
Iterator<String> it = list1.iterator();
int i=0;
while(it.hasNext()){
String s = it.next();
i++;
if (i==2){
it.remove();
System.out.println("removed: "+ s);
}
}
form the doc you can read
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it. In general,
the results of the iteration are undefined under these circumstances.
Some Iterator implementations (including those of all the general
purpose collection implementations provided by the JRE) may choose to
throw this exception if this behavior is detected. Iterators that do
this are known as fail-fast iterators, as they fail quickly and
cleanly, rather that risking arbitrary, non-deterministic behavior at
an undetermined time in the future.
further more, suppose that you can remove item 2 at each iteration. You will end up in a index out of bound exception:
at first iteration you remove item #2 ("Good evening") and list size become 1 (item 0 "hello" and item 1 "World")
at next iteration you remove item #2 which actually does not exist in your list. Your list is indeed of size two, but counter starts from 0, thus you end up removing something which is not there: this is an example of the non-deterministic behavior.
You cann't iterating over an list after the underlying list is modified.if you do that its give you ConcurrentModificationException
to resolve this issue use java.util.ListIterator for iteration of list.
ListIterator<String> it = list1.listIterator();
for (String s : list1) {
if (it.hasNext()) {
String item = it.next();
System.out.println(item);
}
}
You can't delete an item with ArrayList's remove() method while iterating over it. Use Iterator if you want to delete the item also while iterating.
But you are deleting an item based on index then simply moving below line outside the loop will solve your problem.
list1.remove(2);

ConcurrentModificationException when removing an object from ArrayList [duplicate]

This question already has answers here:
Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration? [duplicate]
(11 answers)
Closed 9 years ago.
my classes:
class Game{
ArrayList<Block> blocks;
public ArrayList<Block> getBlocks(){return blocks;};
}
class Block{
if(conditon) {
game.getBlocks().remove(this);
}
}
I have these classes, the ArrayList contains over 10 Block instances, if the condition for remove the current block in the Block class is true, i need remove this block from the ArrayList, but i got the Exception..
While iterating the Arraylist, you are not allowed to remove any item. If you want to remove an item while iteration, you can add removed item into newly created ArrayList say,.
willBeRemovedList after iteration completed you can remove all of them at a time.
ConcurrentModificationException is thrown by iterator because you modified a list and he can't get nextElement because he doesn't know what really happened to list he is iterating over.
for (Block block : blocks) {
blocks.remove(block);
}
This will throw exception when for loop tries to get next element of modified list, since Iterator is instantiated in the beginning of looping through list, iterator will be unable to choose right next element and will throw exception.
You can however remove current element from list you are iterating, but it should be done though Iterator itself. You would do something like this:
for (Iterator<Block> iterator = blocks.iterator(); iterator.hasNext(); iterator.next()){
iterator.remove();
}
The documentation of ArrayList class cleanly tells us the reason and how to avoid it:
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. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future.
If a fail-fast iterator detects
that a modification has been made during iteration, it throws
ConcurrentModificationException, which is an unchecked exception. It is highly probable that you are iterating and modifying your collection in the same loop.
Also, the collections classes in the java.util package all return fail-fast iterators,
which means that they assume a collection will not change its contents during
the time a thread is iterating through its contents.

How does an Iterator throw ConcurrentModificationException on add

How does Iterator throw ConcurrentModificationException when we are adding some object after current node or removing some object after current node. Does Iterator maintain a copy or reference to the underlying collection?
The iterator maintains a reference to the underlying collection. If you add or remove an element, the iterator might be left at an impossible index, or the collection might change "out from underneath" the iterator.
Therefore, instead of letting the iterator get corrupted without letting you know, most collections do the courtesy of throwing a ConcurrentModificationException when you try to modify the collection while iterating, so you don't wind up with unpredictably corrupted iterators.
By contract, you are not allowed to modify the collection while iterating over it (except by using Iterator.remove() et al).
Instead of randomly failing when you do this, the collection is nice enough to keep track of how many times it's been modified, and throw ConcurrentModificationException when it detects concurrent modification.
That ConcurrentModificationException is probably your friend and you ought to learn to live with it. However, just for completeness:
There are non-Oracle collections out there that don't throw ConcurrentModificationException. They're faster (because they don't spend time checking) and, obviously, more flexible, but they require greater care when using.
Oracle has four (at last count) "Concurrent" classes that don't throw it either in java.util.concurrent (ConcurrentHashMap, ConcurrentLinkedQueue, ConcurrentSkipListMap, and ConcurrentSkipListSet). They're marginally slower than their non-concurrent equivalents, but they're thread-safe and they dont block. They won't scramble your data no matter what you do, but they won't stop you from scrambling it.
For removing you can use iterator.remove(), as follows:
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
/* ... */
if (condition) {
iterator.remove();
}
For adding you can replace simple Iterator for ListIterator, as follows
ListIterator<Object> iterator = list.listIterator();
iterator.add(new Object());
Of course an iterator has a link to the underlying collection, this avoids the copy. If you look for example at the source code of ArrayList iterator (ListItr), you'll see it mostly has a link to the list and a cursor.
So, don't share an iterator between threads and don't modify a collection on which you're iterating.

why iterator.remove() has been described as optional operation?

I went through the documentation(http://java.sun.com/javase/6/docs/api/java/util/Iterator.html) of Iterator.remove()
there remove() was described as
void remove()
Removes from the underlying collection the last element returned
by the iterator (optional operation).
This method can be called only once
per call to next. The behavior of an
iterator is unspecified if the
underlying collection is modified
while the iteration is in progress in
any way other than by calling this
method.
So can anybody tell what "optional" means.
Does this affect the robustness of operation?(Like c++ ,it does not guarantee the robustness of the operations.)
Why "optional" has been specified categorically here.
What does "modification" mean in the second line of documentation
behavior of an iterator is unspecified if the underlying collection is modified
#1: Optional means you can implement it or throw an UnsupportedOperationException
#2: This operation is optional because sometimes you just don't want your iterator's content to be modified. Or what do you understand by "robustness of operation"?
EDIT #4: behavior of an iterator is unspecified if the underlying collection is modified
Normally, you use an iterator by executing
List<String> c = new ArrayList<String>();
c.add("Item 1");
c.add("Item 2");
c.add("Item 3");
...
for (Iterator<String> i = c.iterator(); i.hasNext();)
{
String s = i.next();
...
}
If you now would want to remove an item while iterating through the list, and you would call
c.remove("Item 2");
this is not clean, possibly corrupts data in your List/Collection/... and should be avoided. Instead, remove() the item through the iterator:
i.remove();
First of all java.util.Iterator is an interface i.e. an agreement how classes that implement this interface interract with the rest of the world. It's their responsibility how they'll implement interaface's methods.
If the underlying data structure doesn't allow removal then remove() will throw an UnsupportedOperationException. For example, if you are iterating through a result set retrieved from a DB it does make sense not to implement this method.
If you iterate over some collection which is shared between concurrent threads and the other thread modifies the data iterating thread then will return undeterministic results.
It is described as being optional because not all collection classes that can give you an iterator implement the remove() method in the iterator they return. If the returned iterator doesn't implement it, an UnsupportedOperationException will be thrown.
The normal java.util.ArrayList, java.util.LinkedList and other standard collection classes all implement the remove() method in their iterators, so you can use it safely.

Categories

Resources