Search code examples
javaiteratorhashsetfail-fast

Cannot understand this comment about fail-fast


In HashSet.java in JDK 1.6, there are some comments about the fail-fast property of HashSet's iterator.

The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

I can understand the above paragraph because It's pretty simple and clear, but I cannot understand the following paragraph. I may understand it if I have some simple examples showing that a fail-fast iterator can even fail.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.


Solution

  • EDIT: Sorry I used a list, but it's the same idea. This is about iterator, not the Collection behind it.

    EDIT2: Also this is far more likely to happen in a multi-threaded environment, where you have two threads, one reading, one writing. These are harder to see when you are coding. To fix those you need to implement Read/Write locks on the list to avoid this.

    Here is a code example for the comment:

    Iterator itr = myList.iterator();
    
    while(itr.hasNext())
    {
        Object o = itr.next();
    
        if(o meets some condition)
        { 
            //YOURE MODIFYING THE LIST
            myList.remove(o);
        }
    }
    

    What the specs is saying is that you cannot rely on code like this:

    while(itr.hasNext())
    {
         Object o = itr.next();
    
         try
         {
             if(o meets some condition)
                myList.remove(o);
         }
         catch(ConcurrentModificationException e)
         {
             //Whoops I abused my iterator. Do something else.
         }
    }
    

    Instead you should probably add things to a new list and then switch the myList reference to the one just created. Does that explain the situation?