-2

I try to understand the working of Concurrent modification exception in Java, Initially I tried Concurrent modification exception example with normal ArrayList and HashSet by removing elements while iterating, and then with help of CopyOnWriteArrayList & CopyOnWriteArraySet, I resolved the Concurrent modification exception, Everything works fine. But the problem is, when I implicitly make the set as synchronized with help of Collection.synchronized(set) method, still it throws the Concurrent modification exception. CopyOnWriteArrayList & CopyOnWriteArraySet both are synchronized classes,so it doesnt throw Concurrent modification exception. Collection.synchronized(set) also returns synchronized set, then why it throws the Concurrent modification exception.

Can anyone explain what is issue here?

Here is the sample program,

enter image description here

  • Have you read javadoc for `ConcurrentModificationException`? 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. – Andrey B. Panfilov Oct 30 '22 at 04:37
  • 1
    Please don't post images of text. – tgdavies Oct 30 '22 at 06:23

1 Answers1

1

The "concurrent" in ConcurrentModificationException has nothing to do with threads. In fact, if you concurrently modify a collection in the sense of 'change it from 2 threads simultaneously', you may get a ConcurrentModificationException, but you may not. The JVM has a lot of leeway.

The problem is much, much simpler. You did the following:

  1. Create an iterator() from a list.
  2. After step 1, modify the list (and not via the iterator).
  3. Interact with the iterator made in step 1.

This trivially causes CoModEx, every time:

List<String> list = new ArrayList<String>();
list.add("Apple");
list.add("Pear");
list.add("Orange");

for (String item : list) {
  if (item.equals("Pear")) list.remove(item);
}

Here the list is modified (list.remove(item)) after an iterator is made (for ( x : y) makes an iterator), and then after the modification, the iterator is interacted with (looping that for loop iteracts with it).

Think about it: What does this even mean - what if the change you make affects something you haven't looped over yet. Do you expect the loop to still cover it, or not, or should it depend on where we are in the iteration? These are tricky questions. That's why the answer is 'nope, exception instead'.

So, what do you do?

  1. Use CopyOnWriteArrayList. Which is probably overkill. These more or less let you iterate a copy.
  2. Instead of changing the list, register what you want to change, then after you are done looping, apply it.
  3. Instead of for (String x : y), create a listIterator object and use that. Then, to modify the list, call methods on listIterator to modify it, which is fine.
  4. Use a database.
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72