I have the following code that is throwing a ConcurrentModificationException
for some reason. It's thrown when I run it in a debugger with a breakpoint set in one of threads, but apparently not otherwise. I've confirmed that the class in question is not shared between threads by setting the breakpoint (using IntelliJ) to suspend at the thread level and checking that each class instance belongs to unique threads.
public class EventAccumulator implements Observer {
private AtomicInteger inputCount = new AtomicInteger();
private ArrayDeque<Integer> countsList;
...
private void updatePeriodCount() {
countsList.addFirst(inputCount.get());
inputCount.set(0);
while (countsList.size() >= 30) {
countsList.pollLast();
}
int finalCount = 0;
for (int count : countsList) { //<--ConcurrentModificationException
finalCount += count;
}
...
}
Exception:
Exception in thread "Thread-23" java.util.ConcurrentModificationException
at java.util.ArrayDeque$DeqIterator.next(ArrayDeque.java:648)
at com.abc.dept.featurex.aspectx.a.EventAccumulator.updatePeriodCount(EventAccumulator.java:64)
at com.abc.dept.featurex.aspectx.a.EventAccumulator.access$300(EventAccumulator.java:20)
at com.abc.dept.featurex.aspectx.a.EventAccumulator$EventAccumulatorMaintenanceThread.run(EventAccumulator.java:99)
If the class instance is not shared between threads why is ConcurrentModificationException
thrown? Is this safe to use in non-debug mode (i.e. production) assuming the debug mode is using background threads (i.e. through some optimization) that are not being reported in the IDE?
No, this class is almost certainly not safe to use in production. Debuggers don't normally change the content of a collection. And that's what happened here. The content of countsList was changed, while you were iterating over it.
Try to find the source of the modification with the debugger or with log. Maybe you want to set breakpoints in certain methods of ArrayDequeue or override it and place some log in it.