CopyOnWriteArrayList in Java

Filed Under: Java

CopyOnWriteArrayList in Java is a thread safe implementation of List interface. CopyOnWriteArrayList was added in Java 1.5 and part of Collections framework.

Java ArrayList and ConcurrentModificationException

ArrayList is one of the basic implementations of List interface and it’s part of Java Collections Framework. We can use iterator to traverse through ArrayList elements.

Let’s check a sample program of ArrayList.

ConcurrentListExample.java


package com.journaldev.collections;

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

public class ConcurrentListExample {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        
        // get the iterator
        Iterator<String> it = list.iterator();
        
        //manipulate list while iterating
        while(it.hasNext()){
            System.out.println("list is:"+list);
            String str = it.next();
            System.out.println(str);
            if(str.equals("2"))list.remove("5");
            if(str.equals("3"))list.add("3 found");
            //below code don't throw ConcurrentModificationException
            //because it doesn't change modCount variable of list
            if(str.equals("4")) list.set(1, "4");
        }
    }

}

When we run above program, we get java.util.ConcurrentModificationException as soon as the ArrayList is modified.

It happens because ArrayList iterator is fail-fast by design. What it means is that once the iterator is created, if the ArrayList is modified, it throws ConcurrentModificationException.

If you check the console log, you will notice that exception is thrown by Iterator next() method. If you will look into the ArrayList source code, following method is called everytime we invoke next() on iterator that throws exception.


final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

Here modCount is the ArrayList variable that holds the modification count and every time we use add, remove or trimToSize method, it increments. expectedModCount is the iterator variable that is initialized when we create iterator with same value as modCount. This explains why we don’t get exception if we use set method to replace any existing element.

So basically iterator throws ConcurrentModificationException if list size is changed.

CopyOnWriteArrayList in Java

Java CopyOnWriteArrayList

Sometimes we want to add or remove elements from the list if we find some specific element, in that case we should use concurrent collection class – CopyOnWriteArrayList. This is a thread-safe variant of java.util.ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

CopyOnWriteArrayList introduces extra overload to the processing but it’s very effective when number of modifications are minimal compared to number of traversal operations.

If we change the implementation to CopyOnWriteArrayList, then we don’t get any exception and below is the output produced.


list is:[1, 2, 3, 4, 5]
1
list is:[1, 2, 3, 4, 5]
2
list is:[1, 2, 3, 4]
3
list is:[1, 2, 3, 4, 3 found]
4
list is:[1, 4, 3, 4, 3 found]
5

Notice that it allows the modification of list, but it doesn’t change the iterator and we get same elements as it was on original list.

Comments

  1. Vikas Kumar says:

    Hi Pankaj ,

    As I checked the concept for concurrentmodification exception for ArrayList Object .

    If we perform remove operation during Iteration ,It is working and throwing any exception .

    And In case of add element in ArrayList during Iteration .It is throwing

    Exception in thread “main” java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
    at java.util.AbstractList$Itr.next(Unknown Source)
    at com.collections.ArrayListExample.main(ArrayListExample.java:29)

    1. Aseem says:

      Hi Vikas,

      If we remove the element by using the list.remove() method then it will definitely throw ConcurrentModificationException

      Reason -> In case of the list.remove() method the underlying iterator is not modified.

      Where as in case, when we are using it.remove() (here it is reference for iterator), then it will not throw exception. Here the iterator itself gets modified.

  2. infoj says:

    One diff is that underlying array in ArrayList is not declared volatile where as in CopyOnWriteArrayList underlying object array is declared volatile.

  3. Pankaj Roy says:

    Am not getting concurrent modification exception and am able to change the element and remove the same from the map/concurrentHashMap while inside Iterator?? Can you have a look?

    public class ConcurrentHM {
    public static void main(String[] args) {
    Map map= new HashMap();
    map.put(“1”, “1”);
    map.put(“2”, “1”);
    map.put(“3”, “1”);
    map.put(“4”, “1”);
    map.put(“5”, “1”);
    map.put(“6”, “1”);
    Iterator it = map.keySet().iterator();
    System.out.println(“HashMap befor iterator: “+map);
    while(it.hasNext()){
    String key = it.next();
    if(key.equals(“4”))
    map.remove(key);
    }
    System.out.println(“HashMap after iterator: “+map);

    map= new ConcurrentHashMap();
    map.put(“1”, “1”);
    map.put(“2”, “1”);
    map.put(“3”, “1”);
    map.put(“4”, “1”);
    map.put(“5”, “1”);
    map.put(“6”, “1”);
    Iterator it1 = map.keySet().iterator();
    System.out.println(“ConcurremntHashMap befor iterator: “+map);
    while(it1.hasNext()){
    String key = it1.next();
    if(key.equals(“4”)){
    map.remove(key);
    }

    }
    System.out.println(“ConcurremntHashMap after iterator: “+map);
    }

    }

    Output :
    HashMap befor iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
    HashMap after iterator: {3=1, 2=1, 1=1, 6=1, 5=1}
    ConcurremntHashMap befor iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
    ConcurremntHashMap after iterator: {1=1, 5=1, 6=1, 3=1, 2=1}

    Thanks

    1. Srinivas vootla says:

      there could be chance because what ever the key you are removing from map is the last element ,so there is chance get call map.next()

    2. Jayendran Gurumoorthy says:

      Basically, Map will allow adding/removing elements during Iteration. The Concurrent Modification exception will be thrown only Iterating and Modifying the List and Set. Better read about Iterator and its implementations. Happy learning 😉

  4. naresh says:

    Hai Pankaj

    I cannot understand internal implementaion of below code

    final void checkForComodification() {
    if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
    }
    As you said modCount is the ArrayList variable that holds the modification count and every time we use add, remove or trimToSize method, it increments. expectedModCount is the iterator variable that is initialized when we create iterator with same value as modCount.

    My Question is what is the initial value of at first time of modcount and expectedModcounttime and at when level the exception is thrown. i cannot understand can u please explain briefly.

    1. blogger says:

      the value of the expectedModCount and modCount should the samme before we start iteration over list.
      since each time after modification arraylist increments modCount by 1. – modCount and expectedModCount becomes un equal. so exception gets raised

  5. xinwendashibaike says:

    List list = new ArrayList();
    list.add(“1”);
    list.add(“2”);

    Iterator it2=list.iterator();
    while(it2.hasNext()){
    String hh=(String)it2.next();
    if(hh.equals(“1”)){
    list.remove(0);
    }
    }
    System.out.println(list);

    after list.remove(0) size of list is 1,so loop will stop

  6. Shambhu Shah says:

    Nice explained..well done pankaj.

  7. Bawse says:

    Shouldn’t you pass “5” into the arraylist constructor to avoid java defaulting creating arraylist of size 10?

    1. Pankaj says:

      Yes we can provide that, but it’s an example so I prefer to keep it simple. In real life scenarios, where we want optimization and performance specifying list capacity is beneficial.

  8. Anoj Singh says:

    Hi,

    I want to know if employee class same example instead of String class how can get exception
    ConcurrentModificationException.

    1. Pankaj says:

      change the object type in the list and add some values while iterating.

      1. Anoj Singh says:

        public class Test {
        public static void main(String[] args) {
        List al=new ArrayList();
        Employee ee=new Employee(1,”anoj”);
        Employee ee1=new Employee(2,”hai”);
        al.add(ee);
        al.add(ee1);
        Iterator it=al.iterator();
        while(it.hasNext()){
        Employee hh=(Employee)it.next();
        if(hh.getName().equals(“anoj”)){
        al.remove(0);
        System.out.println(al);
        }

        }
        }}

        but i didn’t get ConcurrentModificationException.

        1. sasidhar says:

          u dint get error for this bcoz,
          ur deleting 1 object from content of 2 objects thats y there is no more objects to read 2 nd time in hasNext()..
          try to add another object after removing object..
          u ll get error..

          1. ANEK SINGH says:

            Explanation given is wrong …
            package com.Ikeacommon.generics;

            import java.util.ArrayList;
            import java.util.*;
            import java.io.*;

            public class ConcurrentModification {
            public static void main(String[] args) {

            List l = new ArrayList();

            l.add(12);
            l.add(13);
            l.add(15);
            l.add(130);
            l.add(483);
            Iterator it=l.iterator();

            System.out.println(“before remove method :”+l);
            while (it.hasNext()){

            int i=it.next();

            if(i==130){l.remove(3);}
            System.out.println(i);
            //it.remove();

            }
            System.out.println(“After remove method:”+l);

            }}
            See here I am removing the 4th element ..after loop continues and read 5th element ..still no Concurrent Modification Exception….

          2. Pankaj says:

            Do following:
            use generics
            think what’s happening in l.remove(3) statement
            print the list size after the while loop. You should have your answer by this time…

          3. Naveen says:

            You are performing operation: remove
            if(i==130){l.remove(3);}

            Now if you look there is no element “3” in your list. Remove method a particular object not from a particular index. So try to remove “130” or some other element which list ‘contains’.

      2. Rani Maddala says:

        HI ANEK SINGH ,

        Instead of if(i==130){l.remove(3);} , if I have l.remove(i) , then it’s throwing an exception.

        But I didn;t understand why it’s not throwing an exception if we gave index.

        Regards
        Rani

        1. Dillip says:

          if you try l.remove(i) then it will throw java.lang.IndexOutOfBoundsException

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