CopyOnWriteArrayList with Read and Update operations simultaneously

In this article, we will discuss how can we achieve both read (iterate) and modify (remove/add) operations simultaneously by 2 different threads using CopyOnWriteArrayList which isn’t possible with simple ArrayList

 

1. ArrayList:

If 2 different threads perform operations on same ArrayList object simultaneously, then compiler will throw ConcurrentModificationException

We will demonstrate a simple example using ArrayList which performs

  • 1st thread iterating or reading element/objects one-by-one
  • 2nd thread removing a particular element from List; while other thread is iterating ArrayList object

IterateAndModifyArrayListSimultaneously.java

package in.bench.resources.concurrent.collection;

import java.util.ArrayList;

// extending Thread class
public class IterateAndModifyArrayListSimultaneously extends Thread {

	// creating ArrayList of type String
	static ArrayList<String> alStars = new ArrayList<String>();

	@Override
	public void run() {

		try {
			// sleeping thread for 1000 ms
			Thread.sleep(1000);

			// removing element at 2nd position
			String star = alStars.remove(1);
			System.out.println("Thread 2: removed " + star);
		}
		catch(InterruptedException iex) {
			iex.printStackTrace();
		}
		System.out.println("Removal is done... !!");
	}

	/**
	 * main() method
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {

		// adding elements to ArrayList
		alStars.add("Rock Star");
		alStars.add("Ultimate Star");
		alStars.add("Little Star");

		// creating another thread
		Thread newThread = new Thread(
				new IterateAndModifyArrayListSimultaneously());
		newThread.start();

		// iterating ArrayList using enhanced for-loop
		for(String star : alStars) {

			System.out.println("Thread 1 iterating : " + star);

			// sleeping thread for 1500 ms, after every turn
			Thread.sleep(1500);
		}
		System.out.println("Iterating AL completed... !!");
	}
}

Output:

Thread 1 iterating : Rock Star
Thread 2: removed Ultimate Star
Removal is done... !!
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
	at java.util.ArrayList$Itr.next(ArrayList.java:791)
	at in.bench.resources.concurrent.collection
                           .IterateAndModifyArrayListSimultaneously.main(
                           IterateAndModifyArrayListSimultaneously.java:46)

Explanation:

  • Main thread iterating ArrayList and child thread removing element at 2nd position (index-1) of same ArrayList object
  • From output, it is clear that while one thread is iterating on ArrayList and if any other thread perform modify operation (i.e.; on the same ArrayList object, other thread is removing an element)
  • Then compiler will throw ConcurrentModificationException i.e.; it is fail-fast iterator
  • Note: sleep(ms) introduced to study demo example
  • Because without sleep both thread will execute independently and complete its execution in nano/pico seconds and there won’t be any compile-time error
  • Since we are trying to understand with small amount of data, where execution completes in nano seconds
  • But with large set of data, introduction of sleep concept isn’t required
  • As execution time increases for each thread, definitely ConcurrentModificationException is thrown

 

Q) How to overcome above mentioned problem with ArrayList ?

  • With CopyOnWriteArrayList, we can overcome this problem
  • as it works on different cloned copies which is later merged into one/original copy by JVM

 

2. CopyOnWriteArrayList:

When 2 different threads performs operations on same CopyOnWriteArrayList object simultaneously, then compiler won’t thrown any runtime exception

This is the advantage of using CopyOnWriteArrayList over ArrayList

In the demo example,

  • 1st thread iterates through all elements of CopyOnWriteArrayList
  • While other thread can safely remove element at 2nd position (i.e.; index-1)
  • Compiler doesn’t throws any ConcurrentModificationException unlike ArrayList
  • This is because, CopyOnWriteArrayList works on separate cloned copy and later JVM merges both original & cloned copies

IterateAndModifyCopyOnWriteArrayListSimultaneously.java

package in.bench.resources.concurrent.collection;

import java.util.concurrent.CopyOnWriteArrayList;

// implementing Runnable interface
public class IterateAndModifyCopyOnWriteArrayListSimultaneously
implements Runnable {

	// creating CopyOnWriteArrayList of type String
	static CopyOnWriteArrayList<String> cowalStars = 
			new CopyOnWriteArrayList<String>();

	@Override
	public void run() {

		try {
			// sleeping thread for 1000 ms
			Thread.sleep(1000);

			// removing element at 2nd position
			String star = cowalStars.remove(1);
			System.out.println("Thread 2: removed " + star);
		}
		catch(InterruptedException iex) {
			iex.printStackTrace();
		}
		System.out.println("Removal is done... !!");
	}

	/**
	 * main() method
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {

		// adding elements to CopyOnWriteArrayList
		cowalStars.add("Rock Star");
		cowalStars.add("Ultimate Star");
		cowalStars.add("Little Star");

		// creating another thread
		Thread newThread = new Thread(
				new IterateAndModifyCopyOnWriteArrayListSimultaneously());
		newThread.start();

		// iterating CopyOnWriteArrayList using enhanced for-loop
		for(String star : cowalStars) {

			System.out.println("Thread 1 iterating : " + star);

			// sleeping thread for 1500 ms, after every turn
			Thread.sleep(1500);
		}
		System.out.println("Iterating COWAL completed... !!");
	}
}

Output:

Thread 1 iterating : Rock Star
Thread 2: removed Ultimate Star
Removal is done... !!
Thread 1 iterating : Ultimate Star
Thread 1 iterating : Little Star
Iterating COWAL completed... !!

Explanation:

  • When we executed same program replacing ArrayList with CopyOnWriteArrayList, then program executed without any runtime exception like ConcurrentModificationException i.e.; it is fail-safe iterator
  • But there might be different output at different execution point
  • Because, while one thread iterating on the object it can iterate through all elements or updated items inside ArrayList which is updated by 2nd thread
  • In the above example, we have got all elements of COWAL while iterating; because 2nd thread’s update/removal doesn’t reflected to 1st thread’s iteration/read
  • Same isn’t true with next iteration, because next time there might be possibility of iterating through updated elements of COWAL (in this case 1st thread got updated values from 2nd thread)

 

Lets us print other possibility as well

Output:

Thread 2: removed Ultimate Star
Removal is done... !!
Thread 1 iterating : Rock Star
Thread 1 iterating : Little Star
Iterating COWAL completed... !!

From above output, it is clear that 1st thread got updation from 2nd thread and 1st thread iterated only on updated elements of COWAL

 

References:

 

Happy Coding !!
Happy Learning !!

Remove operation with CopyOnWriteArrayList
CopyOnWriteArrayList class