9

Im trying to delete item from a ArrayList. Some times it pops an exception, java.util.ConcurrentModificationException.

First I tried to remove them by array_list_name.remove(i), but it failed and some people were asked to use Iterator instead. So my current code is as follows:

for (Iterator<Collectable> iter = array_list_name.iterator(); iter.hasNext();) {
   Collectable s = iter.next();
   if (s.equals(array_list_name.get(id))){
       iter.remove();
       return true;
   }
}

And I call array_list_name inside onDraw() function in view. My view is a SurfaceView. Can anyone suggest me how to delete items from ArrayList without getting this error?

xarlymg89
  • 2,552
  • 2
  • 27
  • 41
dinesh707
  • 12,106
  • 22
  • 84
  • 134
  • Problem is unclear to me - you actually use `iter.remove()` **and** see CME, not always but sometimes? – Andreas Dolk Jul 08 '11 at 08:45
  • CME = java.util.ConcurrentModificationException – Leonard Brünings Jul 08 '11 at 08:49
  • Are there any other threads accessing the ArrayList while your iterator is active? – Leonard Brünings Jul 08 '11 at 08:50
  • onDraw() runs on a separate thread and item removal occurs in another. No other threads are used. – dinesh707 Jul 08 '11 at 08:51
  • but the onDraw() method could be called concurrently, right? – Kai Jul 08 '11 at 08:52
  • 1
    Yes, `onDraw` is called in the UI thread so it might be invoked at the same time as item removal in the other thread. – Xion Jul 08 '11 at 08:58
  • 1
    So that is the problem, see the [API](http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove%28%29): `The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress...` – Kai Jul 08 '11 at 09:01

4 Answers4

10

Try using java.util.concurrent.CopyOnWriteArrayList instead of ArrayList

Jorgesys
  • 124,308
  • 23
  • 334
  • 268
Murat Can ALPAY
  • 520
  • 2
  • 17
7

Seems from the comments that your ArrayList<Collectable> is accessed from the onDraw() method in one thread, by the UI, concurrently with you removing items from it in another thread.

So, why not just wrap both accessors in a

synchronized(array_list_name)
{
    // UI access code or item removal code
}

Note that this might make your UI laggy if removing items takes a long time. If this is the case, consider making a list of all item indexes to be removed, and remove them in a tight synchronized loop after iterating over the whole list.

Update

It seems to me your whole code snippet could be simplified to just:

synchronized(array_list_name)
    return array_list_name.remove(id);
Bjarke Freund-Hansen
  • 28,728
  • 25
  • 92
  • 135
1

Have you ever thought to use Vector List ? If you need a thread-safe implementation, you should use Vector instead of ArrayList. Vector list's usage is same with ArrayList. Just change its type with Vector.

Unsafe usage

ArrayList<FutureTask> futureTasks;

Change with

Vector<FutureTask> futureTasks;

That's all.

xarlymg89
  • 2,552
  • 2
  • 27
  • 41
oguzhan
  • 2,073
  • 1
  • 26
  • 23
  • 1
    This is by far the best answer on this thread. Using a class as ```Vector``` that was intented precisely for concurrent usage is the right solution. I've already used in my own project, where I faced a similar problem and was getting ```ConcurrentModificationException```s. Thanks a lot! – xarlymg89 Nov 10 '20 at 11:31
0

You could create a defensive copy of the list like so:

List copy = new ArrayList(array_list_name);
for (Iterator<Collectable> iter = copy.iterator(); iter.hasNext();) {
   Collectable s = iter.next();
   if (s.equals(copy.get(id))){
       iter.remove();
       return true;
   }
}
Tim Büthe
  • 62,884
  • 17
  • 92
  • 129
  • 2
    But this removes the element in the `copy`. The asker might want the element removed in `array_list_name`. If you remove it by its index you can't be sure you get the right element, because the List might have changed. – Kai Jul 08 '11 at 09:03