juergen d
juergen d

Reputation: 204854

Avoid ConcurrentModificationException using Iterator.next()

In my Android app I use this code while drawing some waypoints on a map

Iterator<Waypoint> iterator = waypoints.iterator();
while (iterator.hasNext()) {
   Waypoint w = iterator.next();
}

But I am getting this error

Fatal Exception: java.util.ConcurrentModificationException java.util.ArrayList$ArrayListIterator.next (ArrayList.java:573)

I am not modifying the list directly in the loop I am iterating over.

But it is possible that I modify the list in another thread because a user can move some waypoints. And the drawing of a waypoint can happen the same time a user uses the touch display to move a waypoint.

Can I avoid that exception somehow?

Upvotes: 5

Views: 5688

Answers (3)

v6ak
v6ak

Reputation: 1656

I see some options:

a. Avoid multithreading. Well, you don't have to avoid multithreading completely, just for access to the array. All accesses to the array (even read) must happen from the same thread. Heavy computations can happen on some other threads, of course. This might be a reasonable approach when you can iterate fast.

b. Lock the ArrayList, even for reading. This can be tricky, as excessive locking can introduce deadlocks.

c. Use data copies. Remember, you copy just references, but you usually don't have to clone all the objects. For large data structures, it might be worth considering some persistent data structure, which does not require to copy all the data.

d. Deal with the ConcurrentModificationException somehow. Maybe restart the computation. This might be useful in some cases, but it might get tricky in complex code. Also, in some cases when accessing multiple shared data structures, you might get a livelock – two (or more) threads causing ConcurrentModificationException repeatedly to each other.

EDIT: For some approaches (at least A), you might find reactive programming useful, because this programming style reduces the time spent in the main thread.

Upvotes: -1

Yogesh Badke
Yogesh Badke

Reputation: 4597

The iterator provided by array list is fail-fast iterator - meaning it fails as soon as the underlying list is modified.

One way to avoid the exception is to take a snapshot of the list into another list and then iterate over it.

Iterator<Waypoint> iterator = new ArrayList<>(waypoints).iterator();
while (iterator.hasNext()) {
   Waypoint w = iterator.next();
}

another way is to use collection that implements fail-safe iterators such as CopyOnWriteArrayList.

Upvotes: 1

daniu
daniu

Reputation: 15008

If you want to maintain a List you use in several threads, it's best you use a concurrent list, such as CopyOnWriteArrayList.

Locally, you can avoid the exception by creating a copy of the waypoints list first and iterate that:

Iterator<Waypoint> iterator = new ArrayList<>(waypoints).iterator();
while (iterator.hasNext()) {
    handle(iterator.next());
}

Upvotes: 9

Related Questions