Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fail fast iterator implementation

Tags:

java

iterator

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.

like image 261
Andy897 Avatar asked Oct 08 '13 20:10

Andy897


People also ask

What is a fail-fast iterator?

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.

How is the fail-fast characteristic implemented?

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.

Is ConcurrentHashMap Fail-Safe?

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.

Is Listiterator thread safe?

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.


2 Answers

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.

like image 188
Boris the Spider Avatar answered Sep 30 '22 16:09

Boris the Spider


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.

like image 36
Alowaniak Avatar answered Sep 30 '22 16:09

Alowaniak