Guide to CopyOnWriteArrayList

1. Overview

In this quick article, we’ll be looking at the CopyOnWriteArrayList from the java.util.concurrent package.

This is a very useful construct in the multi-threaded programs – when we want to iterate over a list in a thread-safe way without an explicit synchronization.

2. CopyOnWriteArrayList API

The design of the CopyOnWriteArrayList uses an interesting technique to make it thread-safe without a need for synchronization. When we are using any of the modify methods – such as add() or remove() – the whole content of the CopyOnWriteArrayList is copied into the new internal copy.

Due to this simple fact, we can iterate over the list in a safe way, even when concurrent modification is happening.

When we’re calling the iterator() method on the CopyOnWriteArrayList, we get back an Iterator backed up by the immutable snapshot of the content of the CopyOnWriteArrayList.

Its content is an exact copy of data that is inside an ArrayList from the time when the Iterator was created. Even if in the meantime some other thread adds or removes an element from the list, that modification is making a fresh copy of the data that will be used in any further data lookup from that list.

The characteristics of this data structure make it particularly useful in cases when we are iterating over it more often than we are modifying it. If adding elements is a common operation in our scenario, then CopyOnWriteArrayList won’t be a good choice – because the additional copies will definitely lead to sub-par performance.

3. Iterating Over CopyOnWriteArrayList While Inserting

Let’s say that we’re creating an instance of the CopyOnWriteArrayList that stores integers:

CopyOnWriteArrayList<Integer> numbers 
  = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 8});

Next, we want to iterate over that array, so we are creating an Iterator instance:

Iterator<Integer> iterator = numbers.iterator();

After the Iterator is created, we are adding a new element to the numbers list:

numbers.add(10);

Keep in mind that, when we create an iterator for the CopyOnWriteArrayList, we get an immutable snapshot of the data in the list at the time iterator() was called.

Because of that, while iterating over it, we won’t see the number 10 in the iteration:

List<Integer> result = new LinkedList<>();
iterator.forEachRemaining(result::add);
 
assertThat(result).containsOnly(1, 3, 5, 8);

Subsequent iteration using newly created Iterator will also return the number 10 that was added:

Iterator<Integer> iterator2 = numbers.iterator();
List<Integer> result2 = new LinkedList<>();
iterator2.forEachRemaining(result2::add);

assertThat(result2).containsOnly(1, 3, 5, 8, 10);

4. Removing While Iterating Is Not Allowed

The CopyOnWriteArrayList was created to allow for the possibility of safe iterating over elements even when the underlying list gets modified.

Because of the copying mechanism, the remove() operation on the returned Iterator is not permitted – resulting with UnsupportedOperationException:

@Test(expected = UnsupportedOperationException.class)
public void whenIterateOverItAndTryToRemoveElement_thenShouldThrowException() {
    
    CopyOnWriteArrayList<Integer> numbers
      = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 8});

    Iterator<Integer> iterator = numbers.iterator();
    while (iterator.hasNext()) {
        iterator.remove();
    }
}

5. Conclusion

In this quick tutorial, we had a look at the CopyOnWriteArrayList implementation from the java.util.concurrent package.

We saw the interesting semantics of this list and how it can be iterated in a thread-safe way, while other threads can continue inserting or removing elements from it.

The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.

Related posts:

Java Program to Implement Slicker Algorithm that avoids Triangulation to Find Area of a Polygon
Spring Boot - Securing Web Applications
Easy Ways to Write a Java InputStream to an OutputStream
Convert Hex to ASCII in Java
Count Occurrences of a Char in a String
Hướng dẫn Java Design Pattern – Transfer Object
Introduction to Spring Data JPA
Control Structures in Java
Java Program to Implement Max-Flow Min-Cut Theorem
Java Program to Generate Random Numbers Using Probability Distribution Function
Java Program to Implement Interpolation Search Algorithm
Hướng dẫn sử dụng lớp Console trong java
XML Serialization and Deserialization with Jackson
Wrapper Classes in Java
Java Program to Find the Minimum value of Binary Search Tree
Java Program to Search Number Using Divide and Conquer with the Aid of Fibonacci Numbers
Sao chép các phần tử của một mảng sang mảng khác như thế nào?
Java Program to Implement Double Ended Queue
Tìm hiểu về xác thực và phân quyền trong ứng dụng
Java Program to Find the Median of two Sorted Arrays using Binary Search Approach
Spring Data JPA Delete and Relationships
Send an email with an attachment
Functional Interfaces in Java 8
Java Program to Check whether Graph is a Bipartite using 2 Color Algorithm
Receive email by java client
Feign – Tạo ứng dụng Java RESTful Client
Các nguyên lý thiết kế hướng đối tượng – SOLID
Java Program to Implement Word Wrap Problem
Java Program to Implement Dijkstra’s Algorithm using Priority Queue
Creating a Custom Starter with Spring Boot
Java Program to Implement the Program Used in grep/egrep/fgrep
String Joiner trong Java 8