Concurrent Modification Exceptions with iterators - java

I just have a general question about a program that I am doing.
I have a linked list and one of the instance variable is a version int to make sure there are no concurrent modification exceptions.
If I add an element to the linked list then I change the version.
I also use a custom iterator that iterates through the linked list that also has it's own version. When the linkedList iterator is created, it sets the iterator's version equal to the linkedList's version.
My question is:
If I remove an element with my Iterator should I change the iterators version as well?
Basically every method in the Iterator class it first checks to make sure the versions are the same, and if it's not it throws a new concurrent modification exception.
Does it matter if the iterator changes the list?

My question is: If I remove an element with my Iterator should I change the iterators version as well?
Yes, usually you should also change the version of your Iterator, as long as you want to allow modifications to the list by the Iterator. Otherwise you should throw a java.lang.UnsupportedOperationException.
Have a look at how the Iterator of java.util.LinkedList handles modifications: During the add and remove methods it first calls checkForComodification()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
and at the end it will increase expectedModCount by one:
public void add(E e) {
checkForComodification();
[...]
expectedModCount++;
}

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.

Java sibling removal throws ConcurrentModificationException

I'm having the following issue:
Given:
public class A{
Collection<B> elements = new ArrayList<B>();
}
public class B{
Collection<B> linkedElements = new ArrayList<B>();
}
All the elements of linkedElements belongs to elements too.
I want that each time that an element is deleted from the elements collection, its linked elements gets deleted from that collection too.
I've tried attaching a observer to the Iterator.remove operation and fire there the removal of linkedElements from the elements list, but because of the logic itself, I always run into a ConcurrentModificationException.
Update:
This is the code that causes the error:
public class A{
Collection<B> elements = new ArrayList<B>(){
public Iterator<B> iterator() {
return new ProxyIterator(super.iterator());
};
private class ProxyIterator implements Iterator{
Iterator it;
Object lastObject;
public ProxyIterator(Iterator proxied){
it = proxied;
}
#Override
public boolean hasNext() {
return it.hasNext();
}
#Override
public Object next() {
return lastObject = it.next();
}
#Override
public void remove() {
it.remove()
for (B linkedElement : ((B)lastObject).getlinkedElements()) {
A.this.getElements().remove(linkedElement);
}
}
}
}
With this code, just calling a A.getElements().clear() will fire a ConcurrentModificationException... and its ok, because I'm removing all linked elements from from the elements list while removing one single element. That's why I need another approach.
It's because you're modifying the array while you're iterating over it. From the javadocs for 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. 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.
So, once you do A.this.getElements().remove(linkedElement); in the remove method, you've now just structurally modified the list via a means other than the iterator it's "remove" method, which means the iterator will throw the CME.
Dealing with this will probably be tricky. I can think of a few options offhand, all of which have complications:
Switch to CopyOnWriteArrayList, since its iterators are fail-safe. Downside is that your iterator may potentially still show items that were removed previously. (On the other hand, you have to deal with that sort of risk anyway, since you could also have already iterated past a child of whatever you're removing.) If this works for you, this is almost certainly the easiest and most reliable option.
Following the for loop in remove, replace it with a new Iterator that you manually advance to the correct location. Hard to do if your list allows duplicate items.
Re-implement ArrayList.Iterator; in your remove method, you can track the changes you're making and update your iterator appropriately.
Finally, as a last question / warning - do you want this traversal to be recursive? Right now, if you had elements Foo linked to Bar, and Bar linked to Baz, removing Foo from the iterator would result in Bar being removed, but there's nothing that would then remove Baz. (Whereas if you removed Bar first, then Baz would be removed.) In general if you want to modify the removal behavior of a Collection, you'd be better off doing it List.remove rather than Iterator.remove.

why Vector methods Iterator and ListIterator are fail fast

According to http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html
The Iterators returned by Vector's
iterator and listIterator methods are
fail-fast: if the Vector 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. The Enumerations returned
by Vector's elements method are not
fail-fast. Note that the fail-fast
behavior of an iterator cannot be
guaranteed as it is, generally
speaking, impossible to make any hard
guarantees in the presence of
unsynchronized concurrent
modification. Fail-fast iterators
throw ConcurrentModificationException
on a best-effort basis. Therefore, it
would be wrong to write a program that
depended on this exception for its
correctness: the fail-fast behavior of
iterators should be used only to
detect bugs
Could you give me an example to validate the above set of statements ?Im still unclear with fail fast behaviour of vector's method Iterator and ListIterator.? Confused :-((
if the Vector 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.
Here is an example:
import java.util.*;
public class Test {
public static void main(String[] args) {
List<String> strings = new Vector<String>();
strings.add("lorem");
strings.add("ipsum");
strings.add("dolor");
strings.add("sit");
int i = 0;
Iterator<String> iter = strings.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
// Modify the list in the middle of iteration.
if (i++ == 1)
strings.remove(0);
}
}
}
Output:
lorem
ipsum
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at Test.main(Test.java:18)
The program does the following:
Creates a Vector and gets an iterator
Calls next() twice.
Modifies the vector (by removing the first element)
Calls next() again (after the vector has been modified)
This causes a ConcurrentModificationException to be thrown.
Since Java's for-each loops rely on iterators these constructs may also throw ConcurrentModificationExceptions. The solution is to make a copy of the list before iterating (so you iterate over a copy) or to use for instance an CopyOnWriteArrayList like this:
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class Test {
public static void main(String[] args) {
List<String> strings = new CopyOnWriteArrayList<String>();
strings.add("lorem");
strings.add("ipsum");
strings.add("dolor");
strings.add("sit");
int i = 0;
Iterator<String> iter = strings.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
// Modify the list in the middle of iteration.
if (i++ == 1)
strings.remove(0);
}
}
}
Output:
lorem
ipsum
dolor
sit
A simple way to trigger a concurrent modification exception is
List<String> strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
for(String s: strings)
strings.remove(s);
This triggers an exception because the collection is changed while iteration over the collection.
The reason the Iterator fails fast is to help you detect that a collection was modified concurrently (which these collections don't support) and help detect where the error occurred. If it didn't have this feature you could have subtle bugs which may not show a problem until much later in your code. (Making them much harder to race)
The newer concurrency collections handle concurrent modification differently and don't do this in general. They were introduced into core Java in 2004, i suggest you have a look at these newer collections.
BTW: Don't use Vector unless you have to.
Say you have a Vector of Integers containing 1-10 and you want to remove the odd numbers. You iterate over this list looking for odds and using the Iterators remove() method. After this you have some code that of course assumes there are no odd numbers in the Vector. If another thread modifies the vector during this process, there might sometimes actually be an odd number (depending on the race condition), breaking the code that comes after. Perhaps it doesn't even break right away; maybe it doesn't cause a problem until hours or days later -- very hard to troubleshoot. This is what happens with the elements() method.
Fail-fast means trying to detect this (potential) problem as soon as it occurs and sounding the alarm, which makes it much easier to troubleshoot. As soon as another thread is found to have modified the collection, an exception is thrown. This is what happens with the iterators.
The Iterators returned by iterator() and listIterator() actively watch for unexpected modifications to the underlying list. The Vector class (actually its parent AbstractList), increments a counter each time it is modified. When iterators for the Vector are created, they store a copy of the Vector's modification counter. Each time you call next() or remove() the Iterator compares it's stored value for the counter to the Vector's actual counter. If they differ, it throws a ConcurrentModificationException.

Categories

Resources