Tutorials Logic, IN info@tutorialslogic.com

ConcurrentModificationException in Java Fix: Causes and Fixes

Why This Exception Happens

ConcurrentModificationException happens when a collection is structurally changed while it is being iterated in a way the iterator does not allow. The word concurrent can be confusing: it can happen in a single thread as well as in multi-threaded code.

The most common beginner cause is removing from an ArrayList inside an enhanced for loop. The iterator expects the collection structure to stay stable unless the iterator itself performs the removal.

The fix is to choose the correct removal pattern: Iterator.remove(), removeIf(), collecting changes first, or using a concurrent collection when multiple threads are involved.

In real projects, this exception often appears after a helper method is added inside an existing loop. Review not only the loop body but also every method called inside the loop, because the hidden modification may happen there.

If removal order matters, prefer collecting target items first and removing after iteration. That keeps the loop readable and avoids changing the structure while the iterator is active.

Java collection iterators are fail-fast. They keep an internal modification count and compare it with the collection modification count. If the collection changes unexpectedly, the iterator detects it and throws ConcurrentModificationException.

This protects you from silently skipping elements or reading inconsistent data. It is a debugging signal that your iteration and modification logic need to be separated or coordinated.

  • Adding or removing elements changes the collection structure.
  • Updating a field inside an existing object does not usually count as structural modification.
  • Enhanced for loops use an Iterator internally.
  • Fail-fast behavior is not a thread-safety guarantee.

Safe Fix Patterns

If you need to remove while iterating, use an explicit Iterator and call iterator.remove(). If the condition is simple, removeIf() is shorter and easier to read.

For complex updates, build a second list of items to remove, finish the loop, then call removeAll(). In multi-threaded programs, use CopyOnWriteArrayList, ConcurrentHashMap, synchronization, or another design that avoids unsafely sharing mutable collections.

  • Use Iterator.remove() for controlled removal during iteration.
  • Use removeIf() for predicate-based filtering.
  • Avoid modifying a list inside an enhanced for loop.
  • Use concurrent collections only when the use case really needs shared access.

Debugging Checklist

Find the loop in the stack trace and search for add, remove, clear, or put calls that affect the same collection. Also check methods called inside the loop, because the modification may be hidden in a helper method.

If the issue appears only sometimes, inspect thread access. A background thread, timer, event listener, or request handler may be changing the collection while another part of the program reads it.

  • Check direct modification inside the loop.
  • Check helper methods called from the loop.
  • Check shared static collections.
  • Check event-driven or threaded code that touches the same list.

Match the Fix to Collection Ownership

For a collection owned by one thread, keep mutation inside the iterator operation or defer changes until iteration ends. This preserves a clear order and usually needs no concurrent collection.

For genuinely shared state, define the consistency required by readers. CopyOnWriteArrayList suits read-heavy, small collections because every write copies its backing array. ConcurrentHashMap supports concurrent access with weakly consistent iteration, but compound decisions should use atomic methods such as compute, merge, or remove with an expected value.

  • Use Iterator.remove or removeIf for a single-threaded filtering operation.
  • Use a snapshot only when reading a stable view is more important than seeing every new write.
  • Use concurrent collections for shared ownership, not as a blanket exception workaround.
  • Document whether iteration must observe, ignore, or reject changes made during the traversal.

Wrong: Removing Inside Enhanced for Loop

Wrong: Removing Inside Enhanced for Loop
List<String> names = new ArrayList<>(List.of("Ana", "Bob", "Amit"));

for (String name : names) {
    if (name.startsWith("A")) {
        names.remove(name); // may throw ConcurrentModificationException
    }
}

Correct: Use removeIf

Correct: Use removeIf
List<String> names = new ArrayList<>(List.of("Ana", "Bob", "Amit"));

names.removeIf(name -> name.startsWith("A"));

System.out.println(names); // [Bob]
Before you move on

ConcurrentModificationException in Java Fix: Causes and Fixes Mastery Check

5 checks
  • Find the collection being iterated.
  • Find the structural change made during the iteration.
  • Replace enhanced for removal with Iterator.remove or removeIf.
  • Check whether another thread can modify the same collection.
  • Add a test that removes the first, middle, and last matching item.

ConcurrentModificationException in Java Questions Learners Ask

It's thrown when a collection's structure is modified (add/remove) while iterating over it with an iterator or for-each loop. Java's fail-fast iterators detect this and throw the exception.

Yes! You can modify element values (e.g., list.set(index, newValue)) without causing CME. The exception only occurs when you add or remove elements (structural modifications).

ArrayList and HashMap iterators normally fail fast after an unexpected structural change. CopyOnWriteArrayList iterates over a snapshot, while ConcurrentHashMap iterators are weakly consistent and may reflect some updates. ConcurrentHashMap does not iterate over a copied map.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.