46

I have this little piece of code and it gives me the concurrent modification exception. I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        List<String> s = new ArrayList<>();
        ListIterator<String> it = s.listIterator();

        for (String a : args)
            s.add(a);

        if (it.hasNext())
            String item = it.next();

        System.out.println(s);
    }
}
ilvez
  • 1,235
  • 3
  • 16
  • 27
  • Better to use CopyOnWriteArrayList instad of ArrayList, like List myList = new CopyOnWriteArrayList(); When you are dealing with CopyOnWriteArrayList, u can modify list at runtime and iterator can iterate the list without any problem. – Prashant Agrawal Mar 12 '14 at 05:20

9 Answers9

54

To avoid the ConcurrentModificationException, you should write your code like this:

import java.util.*;

public class SomeClass {

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

        for(String a : args)
            s.add(a);

        ListIterator<String> it = s.listIterator();    
        if(it.hasNext()) {  
            String item = it.next();   
        }  

        System.out.println(s);

    }
}

A java.util.ListIterator allows you to modify a list during iteration, but not between creating it and using it.

fabian
  • 80,457
  • 12
  • 86
  • 114
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
53

I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.

Between creating the iterator and starting to use the iterator, you added arguments to the list that is to be iterated. This is a concurrent modification.

    ListIterator<String> it = s.listIterator();  

    for (String a : args)
        s.add(a);                    // concurrent modification here

    if (it.hasNext())
        String item = it.next();     // exception thrown here

Create the iterator AFTER you've finished adding elements to the list:

    for (String a : args)
        s.add(a); 

    ListIterator<String> it = s.listIterator();  
    if (it.hasNext())
        String item = it.next();
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
12

From the JavaDoc: for ConcurrentModificatoinException: "it is not generally permssible for one thread to modify a Collection while another thread is iterating over it".

It simply means that if you still have an open iterator, you aren't allowed to modify the list because the iterator loop will break. Try moving ListIterator<String> it = s.listIterator(); till after the for loop.

leonm
  • 6,454
  • 30
  • 38
8

You are not allowed to continue iterating over an iterator after the underlying list is modified. Here you create the iterator before adding a few items to s, and then proceed to do a hasNext() and a next() on it after the additions, leading to the ConcurrentModificationException

Yuliy
  • 17,381
  • 6
  • 41
  • 47
5

If the above solutions doesn't work properly. You can use old for-loop for iterating a List at the same time adding new items. See the example below:

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this


        // this will cause ConcurrentModificationException. 
        // Since we are iterating the list, at the same time modifying it.
        /*for(AClass a: aList){
           aList.add(someMethod(a));
        }*/

        // old fashion for-loop will help
        int limit = aList.size();
        for(int i=0; ctr<limit; ++i){
           AClass a = aList.get(i);
           aList.add(someMethod(a));
        }


    }
}
jjz
  • 2,007
  • 3
  • 21
  • 30
  • 2
    From now on I will never ever use for each loop. Using a ListIterator is not cleaner and not using a ListIterator can cause this exception. I would rather add a few more words to the code and be done with it. Old loop forever :p – WVrock Mar 26 '15 at 07:06
  • 1
    Why would you do that? You should understand what you are trying to achieve and use most readable syntax for that. for-each and old for are different. ConcurrentModificationException is there for a reason. – ilvez Nov 30 '15 at 19:12
  • The problem with this approach is that you may miss elements or see elements multiple times due to insertions / deletions made by other threads. Indeed, there is a race condition with a small window where you could get an "index out of bound" exception. – Stephen C May 20 '19 at 01:37
  • Furthermore, if the code that accesses the list is single-threaded, then the "above" solutions **will** work. – Stephen C May 20 '19 at 01:38
  • @jjz where is the code for someMethod(a) and AClass – deepakl.2000 Oct 25 '21 at 15:29
  • @jjz where is the code for someMethod(a) and AClass , ctr is undefined – deepakl.2000 Oct 28 '21 at 06:27
3

to understand this lets look at source of HashMap implementation:

public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{

which contains HashIterator as below:

private abstract class HashIterator {
    ...
    int expectedModCount = modCount;
    ...

    HashMapEntry<K, V> nextEntry() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        .... 
        }

every time you create a iterator:

  • a counter expectedModCount is created and is set to value of modCount as entry checkpoint
  • modCount is incremented in cases of use put/get (add/remove)
  • nextEntry method of iterator is checking this value with current modCount if they are different concurrent modification exception is throw

to avoid this u can:

  • convert map to an array (not recommended for large maps)
  • use concurrency map or list classes (CopyOnWriteArrayList / ConcurrentMap)
  • lock map (this approach removes benefits of multithreading)

this will allow you to iterate and add or remove elements at the same time without rising an exception

Concurrency map/list iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.

More info on CopyOnWriteArrayList

Sevle
  • 3,109
  • 2
  • 19
  • 31
ceph3us
  • 7,326
  • 3
  • 36
  • 43
3

ConcurrentModificationException may arise in both single threaded environment and multi-threaded environment. The main catch is that all the general purpose iterators (like the one used in ArrayList) are all FailFast iterators, which fails when we try to modify one list if one iterator is already iterating over it. Solution - > Use CopyOnWriteArrayList if such scenario is needed by the requirement rather than using ArrayList.

For a complete demo for this, below mentioned code can be used. We just need to change the implementation from CopyOnWriteArrayList to ArrayList.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author narif
 *
 */
public class TestApp {

    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> testList = new ArrayList<>();
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add("abc");
        testList.add(6, "abcAtindex6");
        int size = testList.size();
        System.out.println("The Current List (ArrayList) is: " + testList);
        System.out.println("The size of the List (ArrayList) is: " + size);
        /* Comment the below lines to get the ConcurrentModificationException */
        testList = new CopyOnWriteArrayList<>(testList);
        for (String value : testList) {
            System.out.println("The Value from ForEach Loop is: " + value);
            /*
             * Concurrent modification is happening here
             * One iterator is iterating over the list while we are trying to add new values to
             * the list so the results of the iteration are undefined under these circumstances.
             * So teh fail fast iterators will fail and will throw the ConcurrentModificationException.
             */
            testList.add("valueFromForLoop");
            testList.add("anotherValueFromForEachLoop");
        }
        Iterator<String> it = testList.iterator();
        while (it.hasNext()) {
            String abc = it.next();
            System.out.println(abc);
            testList.add("Value from Iterator1");
            testList.add("Value from Iterator2");
            testList.add("Value from Iterator3");
            testList.add("Value from Iterator4");

        }
        System.out.println("Did the modificationa and all after conevrting the ArrayList to CopyOnWriteArrayList.");
        System.out.println("Calling the method to get the new List..");
        testList = new CopyOnWriteArrayList<>(getTheList(testList));
        for (String value : testList) {
            System.out.println("The value returned from method is : " + value);
        }
    }

    private static List<String> getTheList(List<String> pList) {
        List<String> list = new CopyOnWriteArrayList<>(pList);
        int i = 0;
        for (String lValue : list) {
            System.out.println("The list Passed is " + list);
            i++;
            list.add("localVaueFromMethod" + i);
            list.removeAll(pList);
        }
        return list;
    }

}

For more inifo follow this link this may be helpful alot ConcurrentModificationException Java Docs

Najeeb Arif
  • 404
  • 3
  • 11
  • @Najib Arif For a complete demo for this, below mentioned code can be used. We just need to change the implementation from from ArrayList to CopyOnWriteArrayList ( should be this right ) – deepakl.2000 Oct 28 '21 at 06:20
  • @NajibArif For a complete demo for this, below mentioned code can be used. We just need to change the implementation from from ArrayList to CopyOnWriteArrayList ( should be this right ) – deepakl.2000 Oct 28 '21 at 06:20
1

This didn't work:

LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");

This worked:

LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
Nurgul Alshyn
  • 79
  • 3
  • 11
1

Have a look at oracle documentation page.

public class ConcurrentModificationException
extends RuntimeException

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

In your case, you have modified the collection after creating the iterator and hence you have encountered the exception.

If you change your code as per Stephen C answer, you won't get this error.

oikonomopo
  • 4,025
  • 7
  • 44
  • 73
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211