简体   繁体   中英

Is it possible that I get ConcurrentModificationException when all the methods in my program are synchronized?

I get a ConcurrentModificationException even though I made all the methods of the whole program synchronized (including static methods and the main method).

I don't have hidden iterators.

  1. How is that even possible?!
  2. What does it mean?
  3. How can I fix it?
  1. A ConcurrentModificationException can be caused by the same thread manipulating a collection while iterating over it
  2. It means don't change collections while iterating over them, except through the Iterator.remove() or ListIterator.add() methods
  3. see 2.

You get this exception when you're iterating over a collection and during this you remove an entry from this collection.

eg

Collection<Object> objects = new ArrayList<Objects>(Arrays.asList("a","b"));
for (Object o : objects) {
    objects.remove(o); //throws exception
}

You must add the ones you want to remove to another collection and remove them after your finished iterating over the list. Otherwise, you iterate over the objects collection via it's iterator() and call remove() on the current iterator.

ConcurrentModificationException is NOT related to synchronization.

It's related to modifying a collection while iterating through it. As Lie Ryan points out, a full stack trace would help us point out how you got it.

Generally, to fix this, you must not modify the collection itself while iterating through it.

If you run this

List<Object> list = new ArrayList<Object>();
for(Object obj : list)
    list.remove(obj);

You will get a comodification. You cannot alter a collection while iterating over it without using the appropriate functions.

This can be resolved using the following:

List<Object> list = new ArrayList<Object>();
for(Iterator<Object> itr = list.iterator(); itr.hasNext();)
    itr.remove();

Well, to start with, if you're seeing it, it's possible: if the bird book and the bird disagree, believe the bird.

Now, how can it happen? Hard to say exactly without seeing your code, but the exception stacktrace will point to the place it happened; what do you see around that?

In general, it's going to happen when you have, obviously, concurrent accesses. When you find the place in which it's happening, ask yourself what threads could be getting there.

A synchronized method places a lock on the object instance it's running with.

If objects A and B access the same collection, it doesn't matter if A#doStuff and B#doStuff are synchronized - they can still execute concurrently.

To lock the collection, you probably want a lock on the collection itself: synchronized(collection) in the method bodies, or a Java 5 mutex (better).

(that and the fact that you can have ConcurrentModificationException even in a single thread as others have pointed out).

The javadoc for ConcurrentModificationException contains the answer:

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.

The way to fix it is to not do that.

Ie, (as others have noted) if you need to simultaneously iterate and modify, use the methods supplied by the iterator rather than modifying the collection directly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM