简体   繁体   中英

Why I get ConcurrentModificationException even though I am using locks?

This is my class:

public class AComplicatedclass {
    private List<Connection> activeConnections;
    private Lock lock = new ReentrantLock();          

    public void printConnections() {
        lock.lock();
        for(Connection c : activeConnections){ //exception happens here
            ...prints details about connection
            activeConnections.remove(c);
        }
        lock.unlock();
    }

    private class MyThread extends TimerTask {

        public void run() {
            lock.lock();
                ...can alter activeConnections....
            lock.unlock();
        }

    }
}

As you can see a lock object should prevent problems due to concurrent access to that shared array. Nevertheless, when printConnections() method is called, I get a ConcurrentModificationException in that for .

How come? There is no concurrent modification at all!

Most probably you modify your collection inside the for-loop. As the documentation on ConcurrentModificationException states

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 reason an iterator throws the exception is that it can no longer be determined which element is to be returned next.

So if you want to modify your collection you need to either switch to something like CopyOnWriteArrayList or use the Iterator explicitly as in

    Iterator<Connection> iterator = activeConenctions.iterator();
    while(iterator.hasNext()) {
        Connection c = iterator.next();
        if(/* what ever */) {
            iterator.remove();
        }
    }

Editing a list during a foreach iteration almost always results in a ConcurrentModificationException, even if your application is single threaded.

If you need to remove items during the iteration, use an iterator:

final Iterator<Connection> iterator = activeConnections.iterator();
while(iterator.hasNext()) {
    final Connection connection = iterator.next();
    // ...prints details about connection
    iterator.remove();
}

According to the Javadoc of ConcurrentModificationException :

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.

This has nothing to do with unsynchronized access.

Some examples of problematic operations:

  • the current element of the iteration is removed from the collection, what would be the next element in that case?
  • Some element that was already iterated over is removed and re-inserted later in the collection. Should the iterator show it again when it reaches the new position?

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