8

When I execute the following code, I get ConcurrentModificationException

 Collection<String> myCollection = Collections.synchronizedList(new ArrayList<String>(10));
    myCollection.add("123");
    myCollection.add("456");
    myCollection.add("789");
    for (Iterator it = myCollection.iterator(); it.hasNext();) {
        String myObject = (String)it.next();
        System.out.println(myObject);
        myCollection.remove(myObject); 
        //it.remove();
    }

Why am I getting the exception, even though I am using Collections.synchronizedList?

When I change myCollection to

  ConcurrentLinkedQueue<String> myCollection = new ConcurrentLinkedQueue<String>();

I don't get that exception.

How is ConcurrentLinkedQueue in java.util.concurrent different from Collections.synchronizedList ?

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
Vinoth Kumar C M
  • 10,378
  • 28
  • 89
  • 130

3 Answers3

13

A synchronized List will does not provide a new implementation of Iterator. It will use the implementation of the synchronized list. The implementation of iterator() is:

public Iterator<E> iterator() {
   return c.iterator(); // Must be manually synched by user! 
}

From ArrayList:

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

From ConcurrentLinkedQueue#iterator:

Returns an iterator over the elements in this queue in proper sequence. The returned iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.

The iterators returned by the two collections are different by design.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
8

don't do

myCollection.remove(myObject); 

do

it.remove();

There is no need for synchronization or concurrent collection

unbeli
  • 29,501
  • 5
  • 55
  • 57
  • My question is, how are both different? – Vinoth Kumar C M Jul 06 '11 at 12:55
  • @cmv, it has nothing to do with your list. it has everything to do with you attempting to modify a collection while iterating over it. [`Iterator.remove()`](http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove%28%29) enables you to do this. – mre Jul 06 '11 at 12:59
  • I mean , doesn't Collections.synchronizedList take care of making operations atomic..? – Vinoth Kumar C M Jul 06 '11 at 13:00
  • @cmv: totally different issue. You have one thread here, so Collections.synchronizedList doesn't really do anything. – Jason S Jul 06 '11 at 13:01
  • 4
    @cmv: yes, but (contrary to what the exception name might suggest) this is **not** an issue of multiple threads doing something concurrently. It's an issue of **your single thread** doing structural manipulation of the list (i.e. adding/removing something) while *at the same time* (i.e. *concurrently*) having an active `Iterator` over it. That combination is undefined *unless* you do the structural modification via the `Iterator` itself. – Joachim Sauer Jul 06 '11 at 13:02
  • +1 to @Joachim Sauer for the clean explanation – sutanu dalui Mar 18 '13 at 07:02
2

How is ConcurrentLinkedQueue in java.util.concurrent different from Collections.synchronizedList?

They have different implementations, and therefore may choose whether to throw ConcurrentModificationException, or to handle the situation you describe gracefully. Evidently CLQ handles gracefully, and ArrayList wrapped by Collections.synchronizedList (my guess is the behavior is ArrayList's, not the wrapper's) does not.

As @unbeli says, remove through the iterator, not the collection while iterating.

Jason S
  • 184,598
  • 164
  • 608
  • 970