Arraylist iterator: concurrentmodification - java

occupants is an java.util.ArrayList.
I am iterating through it like so
public void hitOccupants(SnakeController snakeController){
ListIterator<Hitable> i = occupants.listIterator();
while( i.hasNext()){
Hitable hitable = i.next();
if(hitable.hit(snakeController)){//returns true if it should be deleted
i.remove();
}
}
}
I can figure out why this would give a ConcurrenModificationException...
I am using libgdx, so there could be a threading issue. This is my first libgdx project though, so I am not sure. Running the code on android. Stacktrace:
java.util.ConcurrentModificationException
at java.util.AbstractList$SimpleListIterator.remove(AbstractList.java:71)
at com.ninovanhooff.snake.model.BoardSpace.hitOccupants(BoardSpace.java:65)
at com.ninovanhooff.snake.controller.SnakeController.act(SnakeController.java:77)
at com.ninovanhooff.snake.controller.BoardController.act(BoardController.java:72)
at com.ninovanhooff.snake.GameActor$2.act(GameActor.java:77)
at com.badlogic.gdx.scenes.scene2d.Actor.act(Actor.java:86)
at com.badlogic.gdx.scenes.scene2d.Group.act(Group.java:48)
at com.badlogic.gdx.scenes.scene2d.Group.act(Group.java:48)
at com.badlogic.gdx.scenes.scene2d.Stage.act(Stage.java:225)
at com.ninovanhooff.snake.SnakeGame.render(SnakeGame.java:66)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:510)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)

ConcurrentModificationException as per java docs
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.
In short one cannot modify list while iterating through it .
There are multiple ways :
1) Create a new list
2) Use of different collections such as Map or Set.
3) Change some state in hitable object

Hitable.hit() adds an element to the array, thus causing concurrent modification.
To place this into context:
I am making the classic snake game. When the snake hits the Hitable apple:
1) The apple has to be removed from the BoardSpace's occupants //BoardSpace == tile
this is done in the code discussed here
2) The snakeś body is elongated into the BoardSpace where the apple was. The snake is now an occupant of the BoardSpace, thus the snake is added to occupants.
Both these are done inside Apple.hit(), ergo: concurrent modification.
Solution: I used a CopyOnWriteArrayList to trave occupants in the original order and contents, and added the elements to be removed for later removal.
CopyOnWriteArrayList<Hitable> occupantsSnapshot = new CopyOnWriteArrayList<Hitable>(occupants);
ArrayList<Hitable> removals = new ArrayList<Hitable>();
Iterator<Hitable> i = occupantsSnapshot.iterator();
while (i.hasNext()) {
Hitable hitable = i.next();
boolean remove = hitable.hit(snakeController);
if (remove) {//returns true if it should be deleted
removals.add(hitable);
}
}
for(Hitable hitable: removals){
occupants.remove(hitable);
boardController.removeHitable(hitable);
}
For educational purposes: Bitbucket snapshot
See AppleController and SnakeBodyParts.

You're not allowed to remove items from an ArrayList while iterating through it. This is done for a number of reasons. Most obviously, an ArrayList is dynamic, so if you remove the object at index 2, the object at index 3 now shifts down to index 2. This matters because, while iterating, it could easily lead to an out-of-bounds exception if you were to shorten the length of the list without re-adjusting your iterator.
There are a number of ways to get around this, but there's a standing rule: if you're iterating, you can't remove. So either think of a way to do it without iterating (a while loop that only increments the index when hitable.hit is false) or store the objects to be removed in a separate list and then remove those items one by one.

Related

For loop vs. Iterator to avoid ConcurrentModificationException with an ArrayList

Question: What is the optimal (performance-wise) solution for the add, removal, modification of items within an ArrayList which at the same time avoids the ConcurrentModificationException from being thrown during operations?
Context: Based on my research looking into this question, there doesn't seem to be any straight-forward answers to the question at hand - most recommend using CopyOnWriteArrayList, but my understanding is that it is not recommended for array lists of large size (which I am working with, hence the performance-aspect of the question).
Thus, my understanding can be summarized as the following, but want to make sure if is correct/incorrect:
IMPORTANT NOTE: The following statements all assume that the operation is done within a synchronized block.
Remove during iteration of an ArrayList should be done with an Iterator, because for loop results in unpredictable behavior if removal is done within the middle of a collection. Example:
Iterator<Item> itemIterator = items.iterator();
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
// check if item needs to be removed
itemIterator.remove();
}
For add operations, cannot be done with an Iterator, but can be with ListIterator. Example:
ListIterator<Item> itemIterator = list.listIterator();
while(itemIterator.hasNext()){
\\ do some operation which requires iteration of the ArrayList
itemIterator.add(item);
}
For add operations, a ListIterator does NOT have to be necessarily be used (i.e. simply items.add(item) should not cause any problems).
For add operations while going through the collection can be done with EITHER a ListIterator or a for loop, but NOT an Iterator. Example:
Iterator<Item> itemIterator = item.iterator();
while (itemIterator.hasNext()) {
\\ do some operation which requires iteration of the ArrayList
items.add(item); \\ NOT acceptable - cannot modify ArrayList while in an Iterator of that ArrayList
}
Modification of an item within an ArrayList can be done with either an Iterator or a for loop with the same performance complexity (is this true?). Example:
\\ iterator example
Iterator<Item> itemIterator = item.iterator();
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
item.update(); // modifies the item within the ArrayList during iteration
}
\\ for loop example
for (Item item : items){
item.update();
}
Will modification during iteration with the Iterator have the same performance as the for loop? Are there any thread-safety differences between the approaches?
Bonus question: what advantage does using a synchronizedList of the ArrayList for add/remove/modify operations vs. for loop vs. iterator if it also requires a synchronized block?
There is no difference between while loops and for loops and in fact, the idiomatic form of a loop using an iterator explicitly, is a for loop:
for(Iterator<Item> it = items.iterator(); it.hasNext(); ) {
Item item = it.next();
item.update();
}
which gets compiled to exactly the same code as
for(Item item: items) {
item.update();
}
Try it online!
There are no performance differences for identical compiled code dependent to the original source code used to produce it.
Instead of focusing on the loop form, you have to focus on the fundamental limitations when inserting or removing elements of an ArrayList. Each time you insert or remove an element, the elements behind the affected index have to be copied to a new location. This isn’t very expensive, as the array only consists of references to the objects, but the costs can easily add up when doing it repeatedly.
So, if you know that the number of insertions or removals is predictably small or will happen at the end or close to the end (so there is only a small number of elements to copy), it’s not a problem. But when inserting or removing an arbitrary number of elements at arbitrary positions in a loop, you run into a quadratic time complexity.
You can avoid this, by using
items.removeIf(item -> /* check and return whether to remove the item*/);
This will use an internal iteration and postpone the moving of elements until their final position is known, leading to a linear time complexity.
If that’s not feasible, you might be better off copying the list into a new list, skipping the unwanted elements. This will be slightly less efficient but still have a linear time complexity. That’s also the solution for inserting a significant number of items at arbitrary positions.
The item.update(); in an entirely different category. “the item within the ArrayList” is a wrong mindset. As said above, the ArrayList contains references to objects whereas the object itself is not affected by “being inside the ArrayList”. In fact, objects can be in multiple collections at the same time, as all standard collections only contain references.
So item.update(); changes the Item object, which is an operation independent of the ArrayList, which is dangerous when you assume a thread safety based on the list.
When you have code like
Item item = items.get(someIndex);
// followed by using item
where get is from a synchronizedList
or a manually synchronized retrieval operation which returns the item to the caller or any other form of code which uses a retrieved Item outside the synchronized block,
then your code is not thread safe. It doesn’t help when the update() call is done under a synchronization or lock when looping over the list, when the other uses are outside the synchronization or lock. To be thread safe, all uses of an object must be protected by the same thread safety construct.
So even when you use the synchronizedList, you must not only guard your loops manually, as the documentation already tells, you also have to expand the protection to all other uses of the contained elements, if they are mutable.
Alternatively, you could have different mechanisms for the list and the contained elements, if you know what you are doing, but it still means that the simplicity of “just wrap the list with synchronizedList” isn’t there.
So what advantage does it have? Actually none. It might have helped developers during the migration from Java 1.1 and its all-synchronized Vector and Hashtable to Java 2’s Collection API. But I never had a use for the synchronized wrappers at all. Any nontrivial use case requires manual synchronization (or locking) anyway.

Using Iterators to remove elements from a Java Collection

There are many posts that suggest using Iterators to safely remove an element from a collection. Something like this:
Iterator<Book> i = books.iterator();
while(i.hasNext()){
if(i.next().isbn().equals(isbn)){
i.remove();
}
}
According to the documentation, the benefit of using an Iterator is that it is "fail fast" in the sense that if any thread is modifying the collection (books in the above example), while the iterator is used, then the iterator would throw a ConcurrentModificationException.
However, the documentation of this exception also says
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. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
Does this mean that using iterators is not an option if 100% correctness has to be guaranteed? Do I need to design my code in such a way that removal while the collection is modified would always result in correct behavior? If so, can anyone give an example where using the .remove() method of an iterator is useful outside of testing?
Iterator#remove guarantees 100% correctness for single-threaded processing. In multi-threaded processing of data, it depends on how (synchronized/asynchronized processing, using a different list for collecting the elements to be removed etc.) you process the data.
As long as you do not want the same collection to be modified, you can collect the elements to be removed, into a separate List and use List#removeAll(Collection<?> c) as shown below:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Integer> elementsToBeRemoved = new ArrayList<>();
for (Integer i : list) {
if (i % 2 == 0) {
elementsToBeRemoved.add(i);
}
}
list.removeAll(elementsToBeRemoved);
System.out.println(list);
}
}
Output:
[1, 3]
In a loop, never remove elements using the index
For a beginner, it may be tempting to use List#remove(int index) to remove the elements using index but the fact that every remove operation resizes the List makes it produce confusing results e.g.
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
public class Main {
public static void main(String[] args) {
List<Integer> list = new Vector<>();
list.add(1);
list.add(2);
Iterator<Integer> i = list.iterator();
while (i.hasNext()) {
System.out.println("I'm inside the iterator loop.");
i.next();
list.remove(0);
}
System.out.println(list);
}
}
Output:
I'm inside the iterator loop.
[2]
The reason for this output is depicted below:
Iterator.remove will work as long as no other thread changes the Collection while you're iterating over it. Sometimes its a handy feature.
When it comes to multithreaded environment, it really depends on how do you organize the code.
For example if you create a collection inside a web request and do not share it with other requests (for example if it gets passed to some methods via method parameters) you can still safely use this method of traversing the collection.
On the other hand, if you have say a 'global' queue of metrics snapshots shared among all the requests, each request adds stats to this queue, and some other thread reads the queue elements and deletes the metrics, this way won't be appropriate.
So its all about the use case and the how do you organize the code.
As for the example that you're asking for, say you have a collection of Strings and would like to remove all the strings that start with a letter 'a' by modifying the existing collection
Iterator<String> i = strings.iterator();
while(i.hasNext()){
if(i.next().startsWith('a')){
i.remove();
}
}
Of course in Java 8+ you can achieve almost the same with Streams:
strings.stream()
.filter(s -> !s.startsWith('a'))
.collect(Collectors.toList());
However, this method creates a new collection, rather than modifying the existing one (like in the case with iterators).
In pre java 8 world (and iterators have appeared way before java 8 was available), we don't even have streams, so code like this was not really straightforward task to write.
Here is an interesting piece of code (could be a good interview question). Would this program compile? And if so, would it run without exceptions?
List<Integer> list = new Vector<>();
list.add(1);
list.add(2);
Iterator<Integer> i = list.iterator();
while (i.hasNext()) {
i.next();
list.remove(0);
}
Answer : yes. It would compile and run without exceptions. That's because there are two remove methods for the list:
E remove(int index)
Removes the element at the specified position in this list (optional operation).
boolean remove(Object o)
Removes the first occurrence of the specified element from this list, if it is present (optional operation).
And the one that gets called is boolean remove(Object o). Since 0 is not in the list, the list is not modified, and there is no error. This doesn't mean that there's something wrong with the concept of an iterator, but it shows that, even in a single thread situation, just because an iterator is used, does not mean the developer cannot make mistakes.
Does this mean that using iterators is not an option if 100% correctness has to be guaranteed?
Not necessarily.
First of all, it depends on your criteria for correctness. Correctness can only be measured against specified requirements. Saying something is 100% correct is meaningless if you don't say what the requirements are.
There are also some generalizations that we can make.
If a collection (and its iterator) is used by one thread only, 100% correctness can be guaranteed.
A concurrent collection types can be safely accessed and updated via its iterators from any number of threads. There are some caveats though:
An iteration is not guaranteed to see structural changes made after the iteration starts.
An iterator is not designed to be shared by multiple threads.
Bulk operations on a ConcurrentHashMap are not atomic.
If your correctness criteria do not depend one these things, then 100% correctness can be guaranteed.
Note: I'm not saying that iterators guarantee correctness. I am saying that iterators can be part of a correct solution, assuming that you use them the right way.
Do I need to design my code in such a way that removal while the collection is modified would always result in correct behavior?
It depends how you use the collection. See above.
But as a general rule, you do need to design and implement you code to be correct. (Correctness won't happen by magic ...)
If so, can anyone give an example where using the remove() method of an iterator is useful outside of testing?
In any example where only one thread can access the collection, using remove() is 100% safe, for all standard collection classes.
In many examples where the collection is a concurrent type, remove() is 100% safe. (But there is no guarantee that an element will stay removed if another thread is simultaneously trying to add it. Or that it will be added for that matter.)
The bottom line is that if your application is multi-threaded, then you have to understand how different threads may interact with shared collections. There is no way to avoid that.

ConcurrentModificationException removing element from iterator

A ConcurrentModificationException was returned removing an entry from a map but I am unable to see what's wrong.
Iterator<String> mapIterator = this.attributeMap.keySet().iterator();
while (mapIterator.hasNext())
{
String attributeName = mapIterator.next();
if (attributeName.matches(pattern))
{
mapIterator.remove();
}
}
In this case the line
mapIterator.next()
throws ConcurrentModificationException .
The reason behind this is:
There is an int variable modCount which provides the number of times list size has been changed, this value is used in every next() call to check for any modifications in a function checkForComodification(). if mapIterator.next() found change in modCount while iteration object then it will throw ConcurrentModificationException .
To avoid this please follow the below points:
You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.
You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. It is the recommended approach.
You can check this out on some details about CME: https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html
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.
Here are some solutions provided by Baeldung, linked below:
Using an Iterator Directly
Not removing during iteration
Using removeIf()
Filtering using Streams
You can check his site out for the details for each solution to avoid CME: https://www.baeldung.com/java-concurrentmodificationexception
Hope this helps.

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);

How to safely remove other elements from a Collection while iterating through the Collection

I'm iterating over a JRE Collection which enforces the fail-fast iterator concept, and thus will throw a ConcurrentModificationException if the Collection is modified while iterating, other than by using the Iterator.remove() method . However, I need to remove an object's "logical partner" if the object meets a condition. Thus preventing the partner from also being processed. How can I do that? Perhaps by using better collection type for this purpose?
Example.
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
Thanks.
It's not a fault of the collection, it's the way you're using it. Modifying the collection while halfway through an iteration leads to this error (which is a good thing as the iteration would in general be impossible to continue unambiguously).
Edit: Having reread the question this approach won't work, though I'm leaving it here as an example of how to avoid this problem in the general case.
What you want is something like this:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
If you remove objects through the Iterator itself, it's aware of the removal and everything works as you'd expect. Note that while I think all standard collections work nicely in this respect, Iterators are not required to implement the remove() method so if you have no control over the class of myCollection (and thus the implementation class of the returned iterator) you might need to put more safety checks in there.
An alternative approach (say, if you can't guarantee the iterator supports remove() and you require this functionality) is to create a copy of the collection to iterate over, then remove the elements from the original collection.
Edit: You can probably use this latter technique to achieve what you want, but then you still end up coming back to the reason why iterators throw the exception in the first place: What should the iteration do if you remove an element it hasn't yet reached? Removing (or not) the current element is relatively well-defined, but you talk about removing the current element's partner, which I presume could be at a random point in the iterable. Since there's no clear way that this should be handled, you'll need to provide some form of logic yourself to cope with this. In which case, I'd lean towards creating and populating a new collection during the iteration, and then assigning this to the myCollection variable at the end. If this isn't possible, then keeping track of the partner elements to remove and calling myCollection.removeAll would be the way to go.
You want to remove an item from a list and continue to iterate on the same list. Can you implement a two-step solution where in step 1 you collect the items to be removed in an interim collection and in step 2 remove them after identifying them?
Some thoughts (it depends on what exactly the relationship is between the two objects in the collection):
A Map with the object as the key and the partner as the value.
A CopyOnWriteArrayList, but you have to notice when you hit the partner
Make a copy into a different Collection object, and iterate over one, removing the other. If this original Collection can be a Set, that would certaily be helpful in removal.
You could try finding all the items to remove first and then remove them once you have finished processing the entire list. Skipping over the deleted items as you find them.
myCollection<BusinessObject>
List<BusinessObject> deletedObjects = new ArrayList(myCollection.size());
for (BusinessObject anObject : myCollection)
{
if (!deletedObjects.contains(anObject))
{
if (someConditionIsTrue)
{
deletedObjects.add(anObjectsPartner);
}
}
}
myCollection.removeAll(deletedObjects);
CopyOnWriteArrayList will do what you want.
Why not use a Collection of all the original BusinessObject and then a separate class (such as a Map) which associates them (ie creates partner)? Put these both as a composite elements in it's own class so that you can always remove the Partner when Business object is removed. Don't make it the responsibility of the caller every time they need to remove a BusinessObject from the Collection.
IE
class BusinessObjectCollection implements Collection<BusinessObject> {
Collection<BusinessObject> objects;
Map<BusinessObject, BusinessObject> associations;
public void remove(BusinessObject o) {
...
// remove from collection and dissasociate...
}
}
The best answer is the second, use an iterator.

Categories

Resources