This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
Why does the following code throw ConcurrentModificationExcrption, when I clear the sub List after the master List, but not if I clear the sub list and then the master List?
ArrayList<Integer> masterList = new ArrayList<Integer>();
List<Integer> subList;
// Add some values to the masterList
for (int i = 0; i < 10; i++) {
masterList.add(i * i);
}
// Extract a subList from the masterList
subList = masterList.subList(5, masterList.size() - 1);
// The below throws ConcurrentModificationException
masterList.clear();
subList.clear(); // Exception thrown in this line
// The below doesn't throw any exception
subList.clear();
masterList.clear(); // No exception thrown. Confused??
SubList is not an independent entity, but it is just giving a view of the original list, and internally refers to same list. Hence, its design seem to be such that if underlying list is modified structurally (addition/removal of elements), it is not able to fulfill its contract.
As can be seen here in the source code of SubList, the method checkForComodification checks whether the underlying list has been modified, and thus if the modCount (number of times the list has been structurally modified) value of SubList is not same as parent ArrayList, then, it throws ConcurrentModificationException
So, clearing parent ArrayList from which SubList was created can result in the certain operations of SubList to result in ConcurrentModificationException
subList is a view over the masterList. There is just 1 underlying collection. Now masterList is kind of a superset of sublist. So,
sublist cannot exist if masterlist's elements are removed //exception case
masterlist can exist if sublist's elements are removed //OK
acording to ArrayList doc subList() returns a sublist that is backed by the original ArrayList, so if the original changes so does the subList, when you execute subList.clear() the sublist itself doesn't exist anymore.
From the API docs:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
Undefined semantics means of course that it is allowed to throw an exception (and indeed this is probably the wisest course of action).
So you can change the size of the sublist and have those changes reflected in the main list, but the reverse isn't true.
Related
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.
This question already has answers here:
Why am I not getting a java.util.ConcurrentModificationException in this example?
(10 answers)
Closed 8 years ago.
I'm trying to delete an element from an ArrayList inside a loop.
This is OK.
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
for(Integer i: list){
if(i == 2)
list.remove(i);
}
But this is not, and throw concurrentMOdificationException.
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
for(Integer i: list){
list.remove(i);
}
I don't understand why.
I just added another element, it is not OK either (throw concurrentMOdificationException).
ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
System.out.println(list);
for (Integer i : list) {
if (i == 2)
list.remove(i);
}
Use the Iterator class instead of the for-each loop.
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
Integer i = it.next();
it.remove();
}
http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html
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.
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.
You have to understand a little bit about what is going when use a for loop of this nature. It is really using a java.util.Iterator under the hood. This iterator will use the next() method to determine when iteration should stop, and the hasNext() method to retrieve the next element.
The kicker is that only next() checks for concurrent modification - hasNext() does not perform the check. In the first case, you wait until the second loop iteration to remove 2 from the list, and the next iteration finds the end of the list and exits. In the second case, you remove the 1 from the list during the first iteration, and the next iteration throws the exception when it tries to retrieve the next element.
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.
I have created a new ArrayList using subList Method.Now when I try to perform intersection operation using retainAll it Throws following exception
retainAll() Method works for Below Code
List<Integer> arrNums1 = new ArrayList<Integer>();
arrNums1.add(1);
arrNums1.add(2);
arrNums1.add(3);
List<Integer> arrNums2 = arrNums1.subList(0, 1);
arrNums2.retainAll(arrNums1);
But when i try to apply retainAll for Below code it generates Exception as Below
Java Code
public class Generics1
{
public static void main(String[] args)
{
List<Fruits> arrFruits = new ArrayList<Fruits>();
Fruits objApple = new Apple();
Fruits objOrange = new Orange();
Fruits objMango = new Mango();
arrFruits.add(objApple);
arrFruits.add(objOrange);
arrFruits.add(objMango);
List<Fruits> arrNewFruits = arrFruits.subList(0, 1);
System.out.println(arrFruits.retainAll(arrNewFruits));
}
}
class Fruits {}
class Apple extends Fruits {}
class Orange extends Fruits {}
class Mango extends Fruits {}
ERROR
When you use List#subList():
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
You are allowed to mutate elements within it but not change the structure of the list.
The doc further says :
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
The retainAll() function uses an iterator to delete the non intersecting values , this causes ConcurrentModificationException. Note what the documenation says :
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.
Make a copy of the List and then perform retainAll():
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
In your two code examples you have the big list and the sub-list in reverse order.
When you invoke retainAll() on the sub-list, no modifications will occur.
This is because each element in the sub-list is in the big list.
If no modification occurs, no ConcurrentModificationException will be thrown.
You do this above with your list of Integers.
If you reverse the order and invoke retainAll() on the big list, it will get mutated.
This is because not every item in the big list is in the sub-list.
When you remove an element from the big list, a ConcurrentModificationException is thrown.
This is because you cannot mutate a list while iterating over it.
You do this above with your list of Fruits.
The iteration takes place in the retainAll() method.
In your code, the list argument happens to reference the same list that's being modified.
This is because of the way List.subList() works:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
Long story short:
You won't get an Exception If you change your code to this:
System.out.println(arrNewFruits.retainAll(arrFruits));
More importantly:
You need to create a new list from the sub-list if there's a chance that either list will get modified while one of the lists is being iterated over.
You can create a new list from the sub-list like this:
List<Foo> freshList = new ArrayList<Foo>(bigList.subList(0,2));
Now you can iterate and mutate to your heart's content!
Here's an implementation of ArrayList.retainAll(), where you can look for the iteration.
The problem is that arrNewFruits is actually just a logical view of a part of arrFruits.1 To avoid the error, you need to make an independent list:
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
1 That is why you can remove part of a list by calling clear() on a subList()—changes to one are seen in the other.
The following function walks recursively through a list and divide it always by half and do something with the sublists. The recursion breaks when the listsize is 2. I know a concurrent modification exception occurs if I change the list when I iterate over it. But I don't use iterations and it still happens:
private static List<ParticipantSlot> divide(List<ParticipantSlot> list) {
int n = list.size();
//do something
if (n>2){
List<ParticipantSlot> l = divide(list.subList(0, n/2-1));
List<ParticipantSlot> r= divide(list.subList(n/2, n));
l.addAll(r);
return l;
}else{
return list;
}
}
You're using addAll() which will iterate over the collection you provide in the argument. Now subList only returns a view onto the original list, so you're trying to add values onto a view of the original list, and iterate over a different part of the original list at the same time. Bang.
If you created a copy of the sublist each time, it should work - although it'll be pretty inefficient.
You get a concurrent modification exception because sublist is backed by the original list:
The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
If you would like to avoid an exception, make a copy of the first sublist before modifying it.
If you are using ArrayList, you may want to change it to a CopyOnWriteArrayList, or ConcurrentLinkedQueue.
If you are on a Multi-thread environment, you will want to put a synchronized around your Array.
Hope it helps.