15

I'm using Vector instead of ArrayList to make a list safe in multi-threaded enviroment. But I keep getting ConcurrentModificationException when I trying to add items to the Vector while iterating it. Why is that and how can I prevent it?

Shelef
  • 3,707
  • 6
  • 23
  • 28

3 Answers3

9

You cannot modify a Vector while iterating over it. Store the items to add in a separate vector, and move them to the Vector when the loop is finished or loop over a copy of the original Vector.

ADDED: To get a mutex around the Vector in java, do this in both functions:

synchronized (list) {
  // modifying list
}

and:

synchronized (list) {
  // iterating over list
}

Of course I've assumed that the list is named list

fredrik
  • 6,483
  • 3
  • 35
  • 45
  • 4
    Side note: this holds true even in single-threaded programs. – svckr Mar 15 '13 at 16:50
  • what do you mean it holds true in single-threaded programs? – Shelef Mar 15 '13 at 16:55
  • 1
    You can _never_ modify the list while iterating over it. Even in single threaded programs. Modifying the underlying list invalidates the iterator. – fredrik Mar 15 '13 at 16:56
  • so what the purpose of synchronized collections in this case? – Shelef Mar 15 '13 at 16:57
  • None. It only synchronizes direct modifications and reads of the list. Which, in at least Java, does not include Iterators of the list. You need to use a mutex instead - locked for the entire duration of the loop, and which is locked while any other operation is performed on the list. – fredrik Mar 15 '13 at 16:58
  • To prevent another thread from modifying the current thread's view of the list. Note that this does not imply the list is immutable. – Peter Bratton Mar 15 '13 at 16:58
  • "*Store the items to add in a separate vector, and move them to the Vector when the loop is finished or loop over a copy of the original Vector.*" => or use an existing class of the standard JDK which does exactly that: a CopyOnWriteArrayList – assylias Mar 15 '13 at 17:00
  • 1
    @assylias That is not what that class does. It copies the list, throwing away the old one. What I propose is to wait with appending new items until the iterator finished. – fredrik Mar 15 '13 at 17:04
  • I have one method that adds items to the Vector, and another method itareting on the Vector. I synchronized both, is that good idea? – Shelef Mar 15 '13 at 17:11
  • Synchronizing methods will not help - as it only prevents that function from being run concurrently. It does not help with two different functions, they can still be executed concurrently – fredrik Mar 15 '13 at 17:13
  • There is also recommended to declare synchronizing object as final, to sure that it's reference should be changed. – bgplaya Aug 14 '14 at 15:40
2

if you want to add items as you iterate, you'll want to use a ListIterator. by using Vector, you're not bypassing this rule (obviously), so I would recommend using the ArrayList instead.

mre
  • 43,520
  • 33
  • 120
  • 170
  • I don't think it is safe to add while iterating with a ListIterator if more than one thread is involved. – assylias Mar 15 '13 at 16:58
  • 1
    @assylias, I misunderstood the question, I suppose. I was just addressing the `ConcurrentModificationException`. – mre Mar 16 '13 at 01:10
2

If you need to iterate and add concurrently to your list, you should use a concurrent list, such as CopyOnWriteArrayList. Note that if you write a lot to the list it will not be very efficient.

Otherwise, if you use a Vector or a synchronizedList, you need to hold the list's lock while iterating. That will prevent the exception but it will also prevent concurrency...

assylias
  • 321,522
  • 82
  • 660
  • 783