There are similar questions but not exactly what I want to ask. I want to ask how Iterator checks for the modification.
This link says that its implementation is present in AbstractList class where an int variable modCount is defined that provides the number of times list size has been changed. This value is used in every next() call to check for any modifications in a function checkForComodification().
But I could not really understand it. If the value is checked only after every next call then if I do a remove followed by add in the same call, size won't change and modCount should not change as well. But removing and adding in the same loop iteration also throws exception.
Iterators in java are used to iterate over the Collection objects. Fail-Fast iterators immediately throw ConcurrentModificationException if there is structural modification of the collection. Structural modification means adding, removing any element from collection while a thread is iterating over that collection.
The Fail Fast iterators immediately throw ConcurrentModificationException in case of structural modification of the collection. Structural modification means adding, removing, updating the value of an element in a data collection while another thread is iterating over that collection.
concurrent package such as ConcurrentHashMap, CopyOnWriteArrayList, etc. are Fail-Safe in nature. In the code snippet above, we're using Fail-Safe Iterator. Hence, even though a new element is added to the Collection during the iteration, it doesn't throw an exception.
No iterator is thread-safe. If the underlying collection is changed amidst iteration, a ConcurrentModificationException is thrown. Even iterators of synchronized collections are not thread-safe - you have to synchronize manually. One exception is the CopyOnWriteArrayList , which holds a snapshot during iteration.
If you look at the code for a Collection
implementation, lets pick ArrayList
; we have a modCount
variable declared in AbstractList
:
protected transient int modCount = 0;
And then in each and every modifying method (for example remove
) for the ArrayList
we have
public E remove(int index) {
rangeCheck(index);
modCount++;
//....
So the modCount
is only ever incremented; it is never decremented.
In the Iterator
we then have:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Where expectedModCount
is a snapshot of the modCount
taken at Iterator
creation.
So if there is any modification to the underlying List
while the same instance of an Iterator
is in use then a ConcurrentModificationException
will be thrown.
I suppose there is a corner case where if you carried out enough modifications then the int
would overflow and return to it's original value again - this would be a rather large number or modifications however; 232 to be precise.
modCount
always increases when the list is modified (hence mod count) so it should also increase when there's a removal.
Thus it would increase on both the remove and add call.
As Boris the Spider said there is the corner case that modCount
overflows, you can see it by doing:
List<Integer> nums = new ArrayList<>();
for(int i = 0; i < 10; i++) nums.add(i);
for(int n : nums) {
System.out.println(n);
for(int i = -1; i < Integer.MAX_VALUE; i++) {
nums.add(i);
nums.remove(nums.size() - 1);
}
}
Which will (slowly) print 0 through 9 without throwing any exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With