0

I understand that similar questions have been asked before. I just have an additional question.

I have inherited code that is like the following. It is looping over a list using Iterator. The loop does not appear to make any changes to the List. The exception happens with a call to next() method. This is Eclipse RCP code. It is possible that another thread might be modifying the list.

for (Iterator iter = mylist.iterator(); iter.hasNext();) {
    MyItem myItem = (MyItem) iter.next();  // ConcurrentModificationException happens here
    .
    .
    .
}

I tried putting the code in a synchronized block but that did not resolve it. But when I change it to a regular for loop, I do not get the exception.

int list_size = myList.size();
for (int i = 0; i < list_size; i++) {
    MyItem myItem = (MyItem) myList.get(i);
    .
    .
    .
}

Even though I am not getting an exception here, is it possible that the list can still get modified by another thread while the above for loop is in progress? If so what are my alternatives? If I place the for loop in a synchronized block, would it guarantee that the list would not be modified while the loop is in progress?

user2125853
  • 1,265
  • 4
  • 13
  • 23
  • 2
    The alternative is to use a list implementation that is thread safe. What is the type of `mylist`? – luk2302 Aug 14 '19 at 17:27
  • 1
    Check this [Why is a ConcurrentModificationException thrown and how to debug it](https://stackoverflow.com/questions/602636/why-is-a-concurrentmodificationexception-thrown-and-how-to-debug-it) – NullPointerException Aug 14 '19 at 17:33
  • "is it possible that the list can still get modified by another thread while the above for loop is in progress" yes. And if you are not synchronizing access to the list (at *all* places accessing the list), the behaviour is undefined. – Andy Turner Aug 14 '19 at 17:35
  • @luk2302 - MyList is a regular ArrayList – user2125853 Aug 14 '19 at 17:52
  • Re, "I tried putting the code in a synchronized block..." Simply wrapping one routine in a `synchronized` block will _not_ prevent other routines called in other threads from modifying the same data at the same time. The only thing `synchronized (lock)` prevents is, it prevents other threads from synchronizing on the same `lock` at the same time. – Solomon Slow Aug 14 '19 at 18:11
  • I found the answer here https://stackoverflow.com/questions/32718852/concurrentmodificationexception-only-in-java-1-8-0-45. We were sorting the list right before the start of the iteration. – user2125853 Aug 16 '19 at 18:20

1 Answers1

0

If your application is SingleThread, I'd suggest you review your code as this is not to be happening in normal situations.

If your application is a MultiThread application, then you can box your List into the class CopyOnWriteArrayList as shown below. Take a look:

Example:

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.lang.System.out;

public class MyClass {
    public static void main(String[] args) {
        List<Integer> unsynchronizedList =
                IntStream.rangeClosed(0, 100)
                        .boxed()
                        .collect(Collectors.toList());

        final CopyOnWriteArrayList<Integer> synchronizedList = new CopyOnWriteArrayList<>(unsynchronizedList);

        Thread thread = new Thread(new ListIteratorThread(synchronizedList));
        thread.start();

        for (Integer number : synchronizedList) {
            out.println("Main thread says: " + number);
        }
    }

    static class ListIteratorThread implements Runnable {
        private List<Integer> listToIterate;

        ListIteratorThread(List<Integer> listToIterate) {
            this.listToIterate = listToIterate;
        }

        @Override
        public void run() {
            final Iterator<Integer> iterator = listToIterate.iterator();
            Integer number = null;

            while (iterator.hasNext()) {
                number = iterator.next();
            }

            if (number % 2 == 0) {
                listToIterate.remove(number);
            }
        }
    }
}

Hope it helps you :)