Concurrent Modification Exception

java.util.ConcurrentModificationException

The above exception is thrown by java runtime when a collection is modified by a thread, at the same time when another thread is iterating over it in a non-synchronous environment. Let's see an example for the same.

ConModTest.java

package in.techdive.java;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;

public class ConModTest
{
        public ConModTest()
        {
        }

        public static void main(String[] args)
        {
                ConModTest cmT = new ConModTest();
                cmT.listIteration();
        }

        public void listIteration()
        {
                ArrayList<String> lst = new ArrayList<String>();
                lst.add("a");
                lst.add("b");
                lst.add("c");
                lst.add("d");

                Iterator<String> it = lst.iterator();
                while (it.hasNext())
                {
                        String st = it.next();
                        lst.remove(0);
                }
                System.out.println(lst);
        }
}

In the above code in listIteration() method, we create an array list , add elements and get an Iterator from the arraylist. Inside the while loop, array list is iterated, the last line removes an element from arraylist. It means that the Arraylist is structurally modified while being iterated. So the above code throws concurrentModificationException.

To avoid this, once we have created the iterator, we should only remove the arraylist elements using the iterator method. We should only use the iterator methods to modify the arraylist once we have retrieved the iterator. Have a look at the modified version of the above listIteration method.

public void listIteration()
{
        ArrayList<String> lst = new ArrayList<String>();
        lst.add("a");
        lst.add("b");
        lst.add("c");
        lst.add("d");

        Iterator<String> it = lst.iterator();
        while (it.hasNext())
        {
                String st = it.next();
                // lst.remove(0);
                it.remove();
        }
        System.out.println(lst);
}

The functionality of Iterator is such that every-time it is iterated or any element is removed, it checks for the count of the collection which is iterated. If there is a difference in the count, it means that the collection is externally modified then the exception is thrown.

Now consider the case of LinkedHashMap, it maintains the order in which the pairs are entered in to it, while the collection is iterated. There is also a special case of LinkedHashMap, which iterates the Map in terms of access-order. When such a map is iterated, it retrieves elements in the order of elements which are least accessed. Consider the below method.

public void mapIteration()
{
        LinkedHashMap<String, String> lru = new LinkedHashMap<String, String>(16, 0.75f, true);

        lru.put("1", "one");
        lru.put("2", "two");
        lru.put("3", "three");
        lru.put("4", "four");
        lru.get("1");
        System.out.println(lru);

        Set<String> st = lru.keySet();
        for (String s : st)
        {
                System.out.println(s);
                lru.get("4");
        }
}

When the above method is executed, it throws the java.util.ConcurrentModificationException. Oops! How come this is possible? we are not modifying the Map here after getting the iterator.

Yeah, you are right! The problem here is the purpose of the LinkeHashMap is to maintain the order of elements in terms of there access ratio. If an element is accessed less number of times then it is retrieved first using iterator. So after getting either a keySet or Iterator, the Map api methods like get() or put() should not be executed as it will change the iteration order. So structural modification differs for the different set of Maps and collections. For ArrayLists , structural modification means add/delete elements in the ArrayList. For LinkedHashMap (with access order) it means get/put operations in the Map.

So while working with collections, we should take care of above factors to avoid ConcurrentModificationException exception.

Technology: 

Search