Search code examples
javalistcollectionsiteratorconcurrentmodification

Abnormal behaviour of java.util.List based on number of elements in it


I know that if the Collection will be changed while some thread is traversing over it using iterator, the iterator.next() will throw a ConcurrentModificationException.

But it shows different behavior depending on the number of elements in the list.

I tried a code snippet in which I traversed a list in for-each loop and in between it's traversal removed an element from the list using remove() method of the list.

Ideally it should throw a ConcurrentModificationException in this condition without depending on number of elements in the list, But it is not true when number of elements in list are two.

Case 1: Number of elements in list - 1

 public static void main(String[] args) 
    {
        List<String> list=new ArrayList<String>();
        list.add("One");

        for (String string : list) 
        {
            System.out.println(string);
            list.remove(string);
        }
    }

Output: One

Exception in thread "main" java.util.ConcurrentModificationException

That's was as expected.

Case 2: Number of elements in list - 2

 public static void main(String[] args) 
    {
        List<String> list=new ArrayList<String>();
        list.add("One");
        list.add("two");

        for (String string : list) 
        {
            System.out.println(string);
            list.remove(string);
        }
    }

Output: One

No Exception is thrown?????????

Case 3: Number of elements in list - 3

 public static void main(String[] args) 
    {
        List<String> list=new ArrayList<String>();
        list.add("One");
        list.add("Two");
        list.add("Three");

        for (String string : list) 
        {
            System.out.println(string);
            list.remove(string);
        }
    }

Output: One

Exception in thread "main" java.util.ConcurrentModificationException

Again an exception is thrown which is ideal behavior.

But why it runs properly in case-2 without throwing any ConcurrentModificationException.


Solution

  • From the documentation (emphasis mine):

    The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw 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.

    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.