CopyOnWriteArrayList in Java is a thread-safe implementation of a List interface. It belongs to the java.util.concurrent package and is an enhanced version of ArrayList implementation.
As the name suggests, CopyOnWriteArrayList creates a cloned internal copy of the underlying ArrayList for each add() or set() operations. Due to this additional overhead cost, we should ideally use a CopyOnWriteArrayList only when we have very frequent read operations and not many insertions or updations.
We can use one of the following constructors to create a CopyOnWriteArrayList:
Let’s see a few examples:
CopyOnWriteArrayList<String> emptyList = new CopyOnWriteArrayList<>(); //[] list.add("A"); CopyOnWriteArrayList<String> listUsingCollection = new CopyOnWriteArrayList<>(list); //["A"] CopyOnWriteArrayList<String> listUsingArr = new CopyOnWriteArrayList<>(new String[] {"A", "B"}); //["A", "B"]
Just like an ArrayList, it provides implementations for all the methods of the List interface. We can read more about ArrayList here.
As we know, Iterator of ArrayList is fail-fast i.e. it will throw a ConcurrentModificationException when it detects any modification in the list once the iterator is instantiated.
The CopyOnWriteArrayList has a fail-safe iterator and doesn’t throw an exception even when we modify the list during its iteration. This is because the iterator is operating over a cloned internal copy of the original list.
However, any modifications made later to the list won’t be visible to the already instantiated iterator.
Let’s try that out-
Let’s say we have an instance of CopyOnWriteArrayList which currently holds two elements:
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(new String[] {"A", "B"});
Now let’s get an Iterator instance for us to be able to iterate over its elements:
Iterator itr = list.iterator();
After we have created an Iterator instance, let’s now add one more element to our list:
list.add("C"); //doesn't throw an exception
Now, let’s iterator through the elements of our list using itr, we created previously:
while(itr.hasNext()) { System.out.print(itr.next() + " "); }
The above code will print:
A B
As expected, itr doesn’t reflect the current state of the list and only prints “A” and “B” as its elements. However, if we create a new instance of an iterator, it will then represent the exact current state of the list.
The CopyOnWriteArrayList’s Iterator doesn’t support remove() operation. Any attempt to do so will result in an UnsupportedOperationException:
@Test(expected = UnsupportedOperationException.class) public void iterationAndRemoval() { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(new String[]{"A", "B"}); Iterator<String> itr = list.iterator(); while (itr.hasNext()) { itr.remove(); } }
Let’s review the differences between the Java ArrayList and CopyOnWriteArrayList classes:
ArrayList | CopyOnWriteArrayList |
---|---|
Belongs to java.util package and is not thread-safe | Is a thread-safe implementation and is present in the java.util.concurrent packages |
Has a fail-fast Iterator which throws a ConcurrentModificationException when it detects any modification once the iteration starts | Has a fail-safe iterator as the iterator holds a cloned copy of the list |
Iterator supports remove() operation | Its Iterator doesn't supports remove() and throws UnsupportedOperationException for any attempt to do so |
In this tutorial, we learned about a thread-safe implementation of Java List – the CopyOnWriteArrayList. We also covered the difference between the ArrayList and CopyOnWriteArrayList.