java.util.ConcurrentModificationException

Filed Under: Java

java.util.ConcurrentModificationException is a very common exception when working with Java collection classes. Java Collection classes are fail-fast, which means if the Collection will be changed while some thread is traversing over it using iterator, the iterator.next() will throw ConcurrentModificationException. Concurrent modification exception can come in case of multithreaded as well as a single threaded java programming environment.

java.util.ConcurrentModificationException

java.util.ConcurrentModificationException, ConcurrentModificationException, Concurrent Modification Exception, Java ConcurrentModificationException

Let’s see the concurrent modification exception scenario with an example.


package com.journaldev.ConcurrentModificationException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ConcurrentModificationExceptionExample {

	public static void main(String args[]) {
		List<String> myList = new ArrayList<String>();

		myList.add("1");
		myList.add("2");
		myList.add("3");
		myList.add("4");
		myList.add("5");

		Iterator<String> it = myList.iterator();
		while (it.hasNext()) {
			String value = it.next();
			System.out.println("List Value:" + value);
			if (value.equals("3"))
				myList.remove(value);
		}

		Map<String, String> myMap = new HashMap<String, String>();
		myMap.put("1", "1");
		myMap.put("2", "2");
		myMap.put("3", "3");

		Iterator<String> it1 = myMap.keySet().iterator();
		while (it1.hasNext()) {
			String key = it1.next();
			System.out.println("Map Value:" + myMap.get(key));
			if (key.equals("2")) {
				myMap.put("1", "4");
				// myMap.put("4", "4");
			}
		}

	}
}

Above program will throw java.util.ConcurrentModificationException when executed, as shown in below console logs.


List Value:1
List Value:2
List Value:3
Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
	at com.journaldev.ConcurrentModificationException.ConcurrentModificationExceptionExample.main(ConcurrentModificationExceptionExample.java:22)

From the output stack trace, its clear that the concurrent modification exception is coming when we call iterator next() function. If you are wondering how Iterator checks for the modification, its implementation is present in AbstractList class where an int variable modCount is defined. modCount provides the number of times list size has been changed. modCount value is used in every next() call to check for any modifications in a function checkForComodification().

Now comment out the list part and run the program again. You will see that there is no ConcurrentModificationException being thrown now.

Output will be:


Map Value:3
Map Value:2
Map Value:4

Since we are updating the existing key value in the myMap, its size has not been changed and we are not getting ConcurrentModificationException. Note that the output may differ in your system because HashMap keyset is not ordered like a List. If you will uncomment the statement where I am adding a new key-value in the HashMap, it will cause ConcurrentModificationException.

To Avoid ConcurrentModificationException in multi-threaded environment

  1. You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.
  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. This is the recommended approach to avoid concurrent modification exception.

To Avoid ConcurrentModificationException in single-threaded environment

You can use the iterator remove() function to remove the object from underlying collection object. But in this case, you can remove the same object and not any other object from the list.

Let us run an example using Concurrent Collection classes:


package com.journaldev.ConcurrentModificationException;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class AvoidConcurrentModificationException {

	public static void main(String[] args) {

		List<String> myList = new CopyOnWriteArrayList<String>();

		myList.add("1");
		myList.add("2");
		myList.add("3");
		myList.add("4");
		myList.add("5");

		Iterator<String> it = myList.iterator();
		while (it.hasNext()) {
			String value = it.next();
			System.out.println("List Value:" + value);
			if (value.equals("3")) {
				myList.remove("4");
				myList.add("6");
				myList.add("7");
			}
		}
		System.out.println("List Size:" + myList.size());

		Map<String, String> myMap = new ConcurrentHashMap<String, String>();
		myMap.put("1", "1");
		myMap.put("2", "2");
		myMap.put("3", "3");

		Iterator<String> it1 = myMap.keySet().iterator();
		while (it1.hasNext()) {
			String key = it1.next();
			System.out.println("Map Value:" + myMap.get(key));
			if (key.equals("1")) {
				myMap.remove("3");
				myMap.put("4", "4");
				myMap.put("5", "5");
			}
		}

		System.out.println("Map Size:" + myMap.size());
	}

}

The output of the above program is shown below. You can see that there is no ConcurrentModificationException being thrown by the program.


List Value:1
List Value:2
List Value:3
List Value:4
List Value:5
List Size:6
Map Value:1
Map Value:2
Map Value:4
Map Value:5
Map Size:4

From the above example it’s clear that:

  1. Concurrent Collection classes can be modified safely, they will not throw ConcurrentModificationException.
  2. In case of CopyOnWriteArrayList, iterator doesn’t accommodate the changes in the list and works on the original list.
  3. In case of ConcurrentHashMap, the behaviour is not always the same.

    For condition:

    
    if(key.equals("1")){
    	myMap.remove("3");}
    

    Output is:

    
    Map Value:1
    Map Value:null
    Map Value:4
    Map Value:2
    Map Size:4
    

    It is taking the new object added with key “4” but not the next added object with key “5”.

    Now if I change the condition to below.

    
    if(key.equals("3")){
    	myMap.remove("2");}
    

    Output is:

    
    Map Value:1
    Map Value:3
    Map Value:null
    Map Size:4
    

    In this case, it’s not considering the newly added objects.

    So if you are using ConcurrentHashMap then avoid adding new objects as it can be processed depending on the keyset. Note that the same program can print different values in your system because HashMap keyset is not ordered.

Use for loop to avoid java.util.ConcurrentModificationException

If you are working on single-threaded environment and want your code to take care of the extra added objects in the list then you can do so using for loop rather than an Iterator.


for(int i = 0; i<myList.size(); i++){
	System.out.println(myList.get(i));
	if(myList.get(i).equals("3")){
		myList.remove(i);
		i--;
		myList.add("6");
	}
}

Note that I am decreasing the counter because I am removing the same object, if you have to remove the next or further far object then you don’t need to decrease the counter. Try it yourself. 🙂

One More Thing: You will get ConcurrentModificationException if you will try to modify the structure of the original list with subList. Let’s see this with a simple example.


package com.journaldev.ConcurrentModificationException;

import java.util.ArrayList;
import java.util.List;

public class ConcurrentModificationExceptionWithArrayListSubList {

	public static void main(String[] args) {

		List<String> names = new ArrayList<>();
		names.add("Java");
		names.add("PHP");
		names.add("SQL");
		names.add("Angular 2");

		List<String> first2Names = names.subList(0, 2);

		System.out.println(names + " , " + first2Names);

		names.set(1, "JavaScript");
		// check the output below. :)
		System.out.println(names + " , " + first2Names);

		// Let's modify the list size and get ConcurrentModificationException
		names.add("NodeJS");
		System.out.println(names + " , " + first2Names); // this line throws exception

	}

}

Output of above program is:


[Java, PHP, SQL, Angular 2] , [Java, PHP]
[Java, JavaScript, SQL, Angular 2] , [Java, JavaScript]
Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1282)
	at java.base/java.util.ArrayList$SubList.listIterator(ArrayList.java:1151)
	at java.base/java.util.AbstractList.listIterator(AbstractList.java:311)
	at java.base/java.util.ArrayList$SubList.iterator(ArrayList.java:1147)
	at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:465)
	at java.base/java.lang.String.valueOf(String.java:2801)
	at java.base/java.lang.StringBuilder.append(StringBuilder.java:135)
	at com.journaldev.ConcurrentModificationException.ConcurrentModificationExceptionWithArrayListSubList.main(ConcurrentModificationExceptionWithArrayListSubList.java:26)

According to the ArrayList subList documentation, structural modifications is allowed only on the list returned by subList method. All methods on the returned list first check to see if the actual modCount of the backing list is equal to its expected value and throw a ConcurrentModificationException if it is not.

You can download all the example code from our GitHub Repository.

Comments

  1. Suhas says:

    Can you please explain below statement, it’s not very clear.

    To Avoid ConcurrentModificationException in single-threaded environment:
    You can use the iterator remove() function to remove the object from underlying collection object. But in this case, you can remove the same object and not any other object from the list.

    1. Pankaj says:

      It means that if you want to remove the current element, use the iterator.remove() method. You can’t use it to remove any other element from the underlying list.

      If you will use List.remove() method while iterating, you will get ConcurrentModificationException because the List iterator is fail-fast.

      Recommended Read: Java Iterator – Iterator in Java

  2. ABHILASH GUHA says:

    Map i = new HashMap();

    i.put(1, 1);
    i.put(2, 1);
    i.put(3, 1);
    i.put(4, 1);

    Iterator itr = i.keySet().iterator();
    while(itr.hasNext()) {

    Integer key = itr.next();
    if(key.equals(4)) {
    i.put(4, 2);
    i.put(5, 1);
    i.put(6, 1);
    }
    System.out.println(i);
    }

    THe o/p comes as:
    {1=1, 2=1, 3=1, 4=1}
    {1=1, 2=1, 3=1, 4=1}
    {1=1, 2=1, 3=1, 4=1}
    {1=1, 2=1, 3=1, 4=2, 5=1, 6=1}
    Why is no ConcurrentModificationException Coming?

    1. lakshay says:

      As above stated in article that you get Exception on calling iterator.next(); since iterator.next() check for any changes made to collection.

      In your case you are putting elements after the last element; after which there are elements left so hasNext() would return false and itr.next() would not be called so no Exception

  3. anup says:

    Thanks for the article with detailed explanation. One thing is that the checkForComodification() method is present in add() and remove() methods of AbstractList class and that throws ConcurrentModificationException whenever we try to add or remove items. In the article it is mentioned that it is thrown from next() method.
    Kindly let us know the exact behavior.

  4. Abhishek Singh says:

    Hi Pankaj,

    You have mentioned that using synchronized block will prevent ConcurrentModeificationException.
    However when I use it in the example you have given, it still throws ConcurrentModeificationException.
    I tried using synchronized block at various places : like creation of list itself in synchronized block, putting entire code in synchronized block, putting only the iteratior object instantiation and looping in synchronized block.
    But none of it seems to work.

    I even passed class object in sychronized (test,class) but this also didn’t work, tried Collections.synchronizedCollection(myList) but no luck.

    Could you please help?

    Code snippet :
    public class CollectionConcurrentModificationException {

    public static void main(String args[]) {

    List myList = new ArrayList();
    myList.add(“1”);
    myList.add(“2”);
    myList.add(“3”);
    myList.add(“4”);
    //myList.add(“5”);
    Collections.synchronizedCollection(myList);
    //synchronized (myList) {
    Iterator itr = myList.iterator();
    while (itr.hasNext()) {
    String value = (String) itr.next();
    System.out.println(“List value : ” + value);
    System.out.println(“List size :” + myList.size());
    if (value.equals(“3”)) {

    myList.remove(“3”);
    }
    System.out.println(“List size : ” + myList.size());
    }

  5. jnanadeep says:

    The type CopyOnWriteArrayList is not generic; it cannot be parameterized with arguments

    suggest me how to get rid of this error.

    1. Naveen Niraula says:

      There in the article he clearly mentions FOR loops.

      use arrayList.size(); in for loops, maybe ?

  6. Dima says:

    interesting why code with 4 elements do not throw EXEPTION but with 5 element is?

    public static void main(String[] args) {

    List l = new LinkedList();
    l.add(“1”);
    l.add(“2”);
    l.add(“3”);
    l.add(“4”);
    //l.add(“5”);

    Iterator r = l.iterator();
    while (r.hasNext()){
    String x = r.next();
    System.out.println(“List Value:”+x);

    if(x.equals(“3”)){
    l.remove(x);
    };
    }
    System.out.println(l.toString());
    };

  7. priya97 says:

    if we will add element using sublist name then no exception , and original list will aslo get moified automatically….
    why no exception ????
    import java.util.*;
    import java.lang.*;
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    /* Name of the class has to be “Main” only if the class is public. */
    class Codechef
    {
    public static void main (String[] args) throws java.lang.Exception
    {
    // your code goes here

    List names = new ArrayList();
    names.add(“Java”); names.add(“PHP”);names.add(“SQL”);names.add(“Angular 2″);

    List first2Names = names.subList(0, 2);

    System.out.println(names +” , “+first2Names);

    first2Names.set(1, “JavaScript”);

    System.out.println(names +” , “+first2Names);

    //Let’s modify the list size and get ConcurrentModificationException
    first2Names.add(“NodeJS”);
    first2Names.add(“NodeJSkkk”);
    System.out.println(names +” , “+first2Names);
    //this line throws exception
    //names.add(“Javapp”);
    //System.out.println(names +” , “+first2Names);

    }

    }

    1. SUBARNA SEKHAR MUNI says:

      Hi Priya,

      Change in ArrayList object reflects on subList, therefore the change in ArrayList leads to CocurrentModificationException. But a change in subList doesn’t affect to ArrayList in any manner, therefore it doesn’t lead to an error.

  8. rp says:

    In the example to overcome ConcurrentModificationException in single thread env, you have used list and maps remove(). Instead you wanted to use it.remove(). Isn’t it?

  9. vivek singh says:

    Great work, your blog helps a lot. Thanks a lot.

  10. Saurabh Gandhi says:

    Great Article, kudos to you 😊

  11. Ram Thota says:

    package com.journaldev.examples;

    import java.util.ArrayList;
    import java.util.List;

    public class ArrayListSubListExample {

    public static void main(String[] args) {

    List names = new ArrayList();
    names.add(“Java”); names.add(“PHP”);names.add(“SQL”);names.add(“Angular 2″);

    List first2Names = names.subList(0, 2);

    System.out.println(names +” , “+first2Names);

    names.set(1, “JavaScript”);
    //check the output below. 🙂
    System.out.println(names +” , “+first2Names);

    //Let’s modify the list size and get ConcurrentModificationException
    names.add(“NodeJS”);
    System.out.println(names +” , “+first2Names); //this line throws exception

    }

    }

    output:

    [Java, PHP, SQL, Angular 2] , [Java, PHP]
    [Java, JavaScript, SQL, Angular 2] , [Java, JavaScript]
    Exception in thread “main” java.util.ConcurrentModificationException
    at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
    at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
    at java.util.AbstractList.listIterator(AbstractList.java:299)
    at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
    at java.util.AbstractCollection.toString(AbstractCollection.java:454)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.journaldev.examples.ArrayListSubListExample.main(ArrayListSubListExample.java:23)

    After setting “javascript” in names at 1
    we are not updating first2Names
    But first2Names having the value “javascript”.

    How? Can You please explain explain this?

    1. SUBARNA SEKHAR MUNI says:

      TIll the time your size has not changed for the ArrayList, subList can use the modified value as modCount value remains same. Therefore the change reflects (Replacement of Javascript), but when we add another value to the ArrayList then the modCount value changes, therefore it leads to the error.

  12. V J reddy says:

    Hi Pankaj ,

    This is VJ Reddy,

    I have lot of elements which collection i have to choose(i don’t want to order and unique values).

    already i said to array list ,Immediately they raised it’s perfomance problem.

    which one is prefereable.

    waiting for your response.

  13. Suma Gopalakrishna says:

    Thank You for solving the ConcurrentModificationException mystery.

  14. sagar says:

    List myList = Collections.synchronizedList(new ArrayList());

    myList.add(“1”);
    myList.add(“2”);
    myList.add(“3”);
    myList.add(“4”);
    myList.add(“5”);
    synchronized(myList) {
    Iterator it = myList.iterator();
    while(it.hasNext()){
    String value = it.next();
    System.out.println(“List Value:”+value);
    if(value.equals(“3”)) myList.remove(value);
    }
    }

    Got output for above changes in your code, please explain –
    List Value:1
    Exception in thread “main” List Value:2
    List Value:3
    java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at com.fiserv.permission.utility.Demo.main(Demo.java:27)

    1. Pankaj says:

      What is here to explain, your program is similar to my initial program and hence the exception.

      1. Thibault says:

        Thank you for this useful article. In my case, the CopyOnWriteArrayList did the trick.

  15. Tran Nam Long says:

    Good article!

  16. xinwendashibaike says:

    List Value:1
    List Value:2
    List Value:3
    List Value:4
    List Value:5
    List Size:6
    Map Value:1
    Map Value:2
    Map Value:4
    Map Value:5
    Map Size:4

    this is my result.I didn’t get null.

    Map Value:1
    Map Value:null
    Map Value:4
    Map Value:2
    Map Size:4
    there is a null,Why?

    1. Pankaj says:

      Try to run the program multiple times, since HashMap keyset are not ordered like List, output can differ.

  17. jess says:

    ConsurrentHashMmap and copyOnWriteArrayList are fail-safe then while making changes in the list like removing an element etc. is not allowing to add new values in the map.

    Please explan te following piece of code. How come value 4 is added and not 5. Is the null value also counted in the size().

    Iterator it1 = myMap.keySet().iterator();
    while(it1.hasNext()){
    String key = it1.next();
    System.out.println(“Map Value:”+myMap.get(key));
    if(key.equals(“1”)){
    myMap.remove(“3”);
    myMap.put(“4”, “4”);
    myMap.put(“5”, “5”);
    }
    }

    System.out.println(“Map Size:”+myMap.size());
    }

    }

    1. Pankaj says:

      HashMap can have null value, so it will be counted in the size of HashMap.

  18. Binh Thanh Nguyen says:

    Thanks, nice tips

  19. Vivek says:

    Perfect.
    Hope to see more on ConcurrentHashMap.

    1. Pankaj says:

      Okay, I will write soon on ConcurrentHashMap. Thanks for the tip.

  20. Tiru says:

    For the List use case, instead of myList.remove(object), using it.remove() works.

    1. Pankaj says:

      Yes this is the right way to remove an element from collection.

  21. Rob says:

    Thanks alot mate. Explained really neat and simple.

    1. Pankaj says:

      Thanks for nice words Rob.

  22. RaviKant Gaur says:

    nice explanation on ConcurrentModificationException….thnanks,

    1. Pankaj says:

      you are welcome Ravikant.

  23. SwethaHarshini says:

    for(int i = 0; i<myList.size(); i++){
    System.out.println(myList.get(i));
    if(myList.get(i).equals("3")){
    myList.remove(i);
    i–;
    myList.add("6");
    }
    }

    Getting ArraysIndexOutOfBoundsException with this code….could you please explain?

  24. Myrna says:

    Hi,
    Could u please explain me , how come size of myList is 6 though you are adding 5 elements to it in the above program.

    1. Pankaj says:

      Because of this code:

      if(value.equals(“3”)){
      myList.remove(“4”);
      myList.add(“6”);
      myList.add(“7”);
      }

      So 5-1+2=6

      1. Myrna says:

        Thanks for answering my question.

        As u said in below sentence

        In case of CopyOnWriteArrayList, iterator doesn’t accomodate the changes in the list and works on the original list?

        then why does Itereator is allowing size of list to change from 5 to 6?

        1. Pankaj says:

          You are missing the point here, iterator is working on the initial list but list is changed and hence the size of the list. Notice that size is of the list and not of the iterator elements.

          1. Myrna says:

            Thank you for the reply..i completely forgot abt the list and thinking only abt iterator..

  25. shashank says:

    Map Value:1
    Map Value:null
    Map Value:4
    Map Value:2
    Map Size:4

    It is taking the new object added with key “4″ but not the next added object with key “5″.

    What is the reason for this behavior of concurrenthashmap , is it because of 1st its finds the segment and the it find the location of bucket where actually values goes , is that not happening here or i’m missing something , let me know ?

    1. Ashish says:

      Please see below for your quries –

      ConcurrentHashMap achieves higher concurrency by slightly relaxing the promises it makes to callers. A retrieval operation will return the value inserted by the most recent completed insert operation, and may also return a value added by an insertion operation that is concurrently in progress (but in no case will it return a nonsense result). Iterators returned by ConcurrentHashMap.iterator() will return each element once at most and will not ever throw ConcurrentModificationException, but may or may not reflect insertions or removals that occurred since the iterator was constructed. No table-wide locking is needed (or even possible) to provide thread-safety when iterating the collection. ConcurrentHashMap may be used as a replacement for synchronizedMap or Hashtable in any application that does not rely on the ability to lock the entire table to prevent updates

  26. chandra prakash says:

    niche questionire.
    thanks to you sir for ur valuable supprot through yours site for the Interviewees.

  27. Siavash says:

    I don’t get your explanation as why:

    “It is taking the new object added with key “4″ but not the next added object with key “5″.”

    Can you clarify this? Why iterator for ConcurrentHashMap considers 4 but not 5? Debugging this the keyset gets updates and iterator only sees 4 and not 5

  28. sima says:

    I want to start learning java,please help me how can I learn and improve?

  29. Ed says:

    In your examples you are modifying the collection that you are iterating over. To avoid the concurrent modification exception why not collect up a number of objects you want to remove and remove them post iteration?

    1. Pankaj says:

      Suppose we need to remove 100 objects from a list of 10000 objects, then remove function will take lot of time and memory, so its better to use it this way.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages