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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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.
1 2 3 4 5 6 |
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
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.
1 2 3 4 5 6 7 8 9 10 11 12 |
<span style="color: #008000;"><strong><code> 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 </code></strong></span> |
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.