Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can using foreach of CopyOnWriteArrayList cause ConcurrentModificationException in java?

I look to java 11 implementation of .foreach method in CopyOnWriteArrayList

public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    for (Object x : getArray()) {
        @SuppressWarnings("unchecked") E e = (E) x;
        action.accept(e);
    }
}

I see that it just loops the array without any locks.
Can add() or remove() performed concurrently with foreach give a ConcurrentModificationException?
In contrast to iterator(), foreach seems to avoid using the copy of original array on write and it uses no locks.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Can using foreach of CopyOnWriteArrayList cause ConcurrentModificationException in java?

No. You can see that from the code that it doesn’t throw ConcurrentModificationException:

public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    for (Object x : getArray()) {
        @SuppressWarnings("unchecked") E e = (E) x;
        action.accept(e);
    }
}

Note that getArray() call is not copying the array. It is declared like this:

private transient volatile Object[] array;

final Object[] getArray() {
    return array;
}

(Since array is volatile, no lock is needed to ensure that getArray() returns the current version of the array.)


Can add() or remove() performed concurrently with foreach give a ConcurrentModificationException?

A call to those methods will cause a new backing array to be created with the update. This is done holding a lock on the CopyOnWriteArrayList, and then the array is replaced.

Meanwhile, the foreach() call will loop over the old array as if nothing happened.


In contrast to iterator(), foreach seems to avoid using the copy of original array on write and it uses no locks.

Actually, iterator() behaves the same way as foreach. It calls getArray() to get the current backing array.

public Iterator<E> iterator() {
    return new COWIterator<E>(getArray(), 0);
}

And if you look at the COWIterator class, it doesn’t throw ConcurrentModificationException either.


Note that this is all specified in the javadocs.

  1. The javadocs for CopyOnArrayList state:

    "… the iterator is guaranteed not to throw ConcurrentModificationException."

  2. The javadocs for foreach (in Iterable) state:

    "The default implementation behaves as if:"

    for (T t : this)
    action.accept(t);

    which is using the iterator provided by CopyOnArrayList that doesn’t throw ConcurrentModificationException; see 1.


However, there is a small gotcha. A sublist of a CopyOnWriteList is not a CopyOnWriteList, and it can produce a ConcurrentModificationException; see CopyOnWriteArrayList throwing CurrentModificationException

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading