Java CopyOnWriteArrayList with example . Solution for ConcurrentModificationException / iterators fail-fast

Vector and Synchronized ArrayList are not fully thread safe. Both are conditionally thread-safe that means all the individual operations (methods) are thread-safe. For example, many number of threads can call the add() method of a Vector or Synchronized ArrayList simultaneously to add elements to the list. This concurrent operation will never fail because add() method is synchronized (not applicable for ArrayList). But when one thread changes the List by mutative operations (add, remove , etc), while another thread is traversing it through an Iterator, the iterator implemented in the java.util Collections classes fails by throwing ConcurrentModificationException ( see Example 1 ). The exception occurs when the hasNext() or next() method of Iterator class is called. The same error also occurs (See example 2) , when elements are added in ArrayList or Vector, after iterator() method is called .

Example 1:


package com.javaonline;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;

public class ConcurrentModificationExceptionTest2 {
 public static void main(String[] args) throws InterruptedException {
 List list = new Vector();

//CopyOnWriteArrayList list=new CopyOnWriteArrayList();

 for (int i = 0; i< 1000; i++) {
 Thread a1 = new Thread(new addElement(list,i));
 a1.start();
 }
 Thread p1 = new Thread(new printElement(list));
 p1.start();
 }
 }

class addElement implements Runnable {
 private List list;
 private int element;
 public addElement (List myList, int e)
 {
 list = myList;
 element = e;
 }

 public void run() { list.add(element); }
 }

class printElement implements Runnable {
 private List list;
 public printElement (List myList) { list = myList; }

 public void run() {

 Iterator it=list.iterator();
 while(it.hasNext()) System.out.print(it.next()+" ");
 }
 }

Running the above program , throws the following error. May not throw the error for each run. When addElement method and printElement method is called simultaneously, the the following error occurs.

ConcurrentModificationException2

Example 2 :


package com.javaonline;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;
public class ConcurrentModificationExceptionTest {
 public static void main(String args[]) {
 List list=Collections.synchronizedList(new ArrayList());
 //CopyOnWriteArrayList list=new CopyOnWriteArrayList();
 list.add("1");
 list.add("2");
 list.add("3");
 Iterator it = list.iterator();
 list.add("4");
 list.add("5");
 while (it.hasNext()) {
 System.out.print(it.next()+" ");
 }
 }
}

Running the above code will throw the below error

ConcurrentModificationException1

Now one of the solution is to prevent ConcurrentModificationException, we may use the external synchronization to lock the entire List while iterating .Another solution is to use CopyOnWriteArrayList class. We can use CopyOnWriteArrayList (a thread-safe variant of ArrayList ) class as a replacement for ArrayList in concurrent applications where more iterations are required on the ArrayList. This class is packaged with java.util.concurrent . It extends Object and implements List.  Now let us see what happens exactly when we use the class CopyOnWriteArrayList . All mutable operations ( add , remove and so on) make a copy (clone) of original array list ,then make the change to the copy, and finally replace the copy with original array list after the iteration is over. The iterators operates on the original array list at the time the iterator was constructed thus does not throw error ConcurrentModificationException. CopyOnWriteArrayList implementations provide higher concurrency and also preserves thread safety. It is not necessarily to use CopyOnWriteArrayList everywhere instead of ArrayList. It may be used where more concurrent access of mutable operations and iterations over array list are required.

To solve the error of Example 1,

Just uncomment the line

//CopyOnWriteArrayList list=new CopyOnWriteArrayList();

and comment the line

List list=new Vector();.

To solve the error of Example 2,

Uncomment the line

//CopyOnWriteArrayList list=new CopyOnWriteArrayList();

and comment the line

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

The output will be 1 2 3.  It will not print 4 5 because the iterator uses the original arraylist at the time the iterator was constructed.

You may also like

Leave a Reply