Tutorial

java.util.ConcurrentModificationException

Published on August 3, 2022
author

Pankaj

java.util.ConcurrentModificationException

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 the 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, it’s clear that the concurrent modification exception is thrown when we call iterator next() function. If you are wondering how Iterator checks for the modification, it’s implementation is present in the AbstractList class, where an int variable modCount is defined. The modCount provides the number of times list size has been changed. The 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:

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. The output may be different 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’s 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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Pankaj

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
October 3, 2020

Hey Man You Are Really Awesome… You Save My Time … Praying For Your Good Health… i am From Bangladesh…

- Arif

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    October 4, 2019

    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.

    - Suhas

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      October 8, 2018

      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?

      - ABHILASH GUHA

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        October 5, 2018

        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.

        - anup

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          May 26, 2018

          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()); }

          - Abhishek Singh

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            May 1, 2018

            The type CopyOnWriteArrayList is not generic; it cannot be parameterized with arguments suggest me how to get rid of this error.

            - jnanadeep

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              April 30, 2018

              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()); };

              - Dima

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                March 23, 2018

                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); } }

                - priya97

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  December 15, 2017

                  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?

                  - rp

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    September 5, 2017

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

                    - vivek singh

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Become a contributor for community

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      DigitalOcean Documentation

                      Full documentation for every DigitalOcean product.

                      Resources for startups and SMBs

                      The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                      Get our newsletter

                      Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                      New accounts only. By submitting your email you agree to our Privacy Policy

                      The developer cloud

                      Scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Get started for free

                      Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                      *This promotional offer applies to new accounts only.