Skip to main content

How to synchronize ArrayList in Java

How to synchronize ArrayList in Java?

In this article, we are going to learn how we can synchronize ArrayList in Java. As we know, ArrayList in Java is not thread-safe Collection i.e., not synchronized.

Why ArrayList is not Synchronized?

First, we should know "Why ArrayList is not Synchronized?" before knowing how to make that synchronized. Most of the real-world scenarios need thread-based implementation plus ArrayList can be used as a better alternative to an Array. Hence if ArrayList is synchronized we can easily use ArrayList in the multi-threaded environment. So the question is, Why it is not Synchronized?
The answer lies in terms of the performance aspect. To make any class synchronized, it needs performance overhead. If the ArrayList would be made as synchronized, Each-n-Every operation onto the ArrayList will take some extra time as compared to the current implementation of the ArrayList and, the ArrayList is used widely in the java so the developer of the ArrayList given it as non-synchronized to make it faster and drop "How to synchronize ArrayList in Java?" for us.

Now we know why ArrayList is not synchronized. Let's learn how to synchronize ArrayList in Java. There are two ways to synchronize ArrayList, let's look at them one-by-one.

How to synchronize ArrayList in Java - Using Collections.synchronizedList() method?

The synchronizedList() is a static method of java.util.Collections class. This method takes an argument of List<T> type and return an instance of List<T> type but the returned List is synchronized.
Syntax
ArrayList<T> arrayList = new ArrayList<>();
List<T> synchronizedList = Collections.synchronizedList(arrayList);
This returned List is a synchronized List i.e., it is a thread-safe version of the ArrayList. All the method of this ArrayList is synchronized to each other i.e, At any time, only one thread is able to operate any operation onto the ArrayList.
Also, important to note that the iterator provided by this ArrayList is not synchronized. It is recommended to iterate this synchronized ArrayList within the synchronized block or synchronized method otherwise the result may be in non-deterministic behavior.
Read this article to learn different methods to iterate ArrayList in java?

Java Synchronized ArrayList Example 1: iterate synchronized ArrayList using synchronized block.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> books = new ArrayList<>();
        books.add("Learn Java");
        books.add("Coding in Python");
        books.add("Data Structures");
        books.add("Introduction to Database");

        // Synchronized ArrayList
        List<String> synchronizedList = Collections.synchronizedList(books);

        // Starting printingThread-1
        printingThread("Thread-1", synchronizedList);

        // Starting printingThread-2
        printingThread("Thread-2", synchronizedList);
    }

    public static void printingThread(String threadName, List<String> synchronizedList) {
        Runnable runnable = () -> {
            synchronized (synchronizedList) {
                System.out.println(
                    "-------Synchronized Block of " + Thread.currentThread().getName() + " started----------");
                Iterator<String> iterator = synchronizedList.iterator();
                while (iterator.hasNext()) {
                    String element = iterator.next();
                    System.out.println(
                        Thread.currentThread().getName() + " : " + element);
                }
                System.out.println(
                    "-------Synchronized Block of " + Thread.currentThread().getName() + " ended------------");
            }
        };
        Thread thread = new Thread(runnable, threadName);
        thread.start();
    }
}
Output
-------Synchronized Block of Thread-1 started----------
Thread-1 : Learn Java
Thread-1 : Coding in Python
Thread-1 : Data Structures
Thread-1 : Introduction to Database
-------Synchronized Block of Thread-1 ended------------
-------Synchronized Block of Thread-2 started----------
Thread-2 : Learn Java
Thread-2 : Coding in Python
Thread-2 : Data Structures
Thread-2 : Introduction to Database
-------Synchronized Block of Thread-2 ended------------
As you can see, first the synchronized block of Thread-1 has been started, iterate over the synchronized ArrayList and ended. After that, the synchronized block of Thread-2 was started. This happened due to the presence of synchronized block in the thread if we do not use synchronized block then both the thread iterate ArrayList parallelly and during that, if any other thread performs any modification, the ConcurrentModificationException would be raised.

After The Java 8

Java 8 introduced forEach() method to iterate any Collection and as we learn above, all the methods of the synchronized ArrayList are synchronized with each other. Therefore, we can use forEach() method to iterate the synchronized ArrayList without using synchronized block and also we don't need to worry about the other thread working on the same ArrayList as the forEach() method also synchronized with other methods.
Let's understand this with an example:

Java Synchronized ArrayList Example 2: iterate synchronized ArrayList using forEach() method.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> books = new ArrayList<>();
        books.add("Learn Java");
        books.add("Coding in Python");
        books.add("Data Structures");
        books.add("Introduction to Database");

        // Synchronized ArrayList
        List<String> synchronizedList = Collections.synchronizedList(books);

        // Starting printingThread-1
        printingThread("Thread-1", synchronizedList);

        // Starting printingThread-2
        printingThread("Thread-2", synchronizedList);
    }

    public static void printingThread(String threadName, List<String> synchronizedList) {
        Runnable runnable = () -> {
            synchronizedList.forEach(element -> {
                System.out.println(Thread.currentThread().getName() + " : " + element);
            });
        };
        Thread thread = new Thread(runnable, threadName);
        thread.start();
    }
}
Output
Thread-1 : Learn Java
Thread-1 : Coding in Python
Thread-1 : Data Structures
Thread-1 : Introduction to Database
Thread-2 : Learn Java
Thread-2 : Coding in Python
Thread-2 : Data Structures
Thread-2 : Introduction to Database

How to synchronize ArrayList in Java - Using CopyOnWriteArrayList class?

There exist another class in the java.util.concurrent package which is also a thread-safe variant of the ArrayList is known as CopyOnWriteArrayList.
"The CopyOnWriteArrayList class can also be used to synchronize ArrayList in Java, all the modification operation onto the ArrayList like add(), addAll(), set(), remove(), etc. are done by making a fresh copy of the underlying array.
It is recommended to use this class where we need an ArrayList only or mostly for traversal and Any modification operation is less likely to be performed as it requires making a fresh copy of the underlying Array which is a performance over-head task."
It is better to understand with an example:

Java Synchronized ArrayList Example 3: Create synchronized ArrayList using CopyOnWriteArrayList and iterate parallelly.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> books = new ArrayList<>();
        books.add("Learn Java");
        books.add("Coding in Python");
        books.add("Data Structures");
        books.add("Introduction to Database");

        // Synchronized ArrayList
        CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>(books);

        // Starting printingThread-1
        printingThread("Thread-1", copyOnWriteArrayList);

        // Starting printingThread-2
        printingThread("Thread-2", copyOnWriteArrayList);
    }

    public static void printingThread(String threadName, CopyOnWriteArrayList<String> synchronizedList) {
        Runnable runnable = () -> {
            synchronizedList.forEach(element -> {
                // Add delay of 100 milliseconds. Meanwhile, CPU can switch between threads.
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}

                System.out.println(
                    Thread.currentThread().getName() + " : " + element);
            });
        };
        Thread thread = new Thread(runnable, threadName);
        thread.start();
    }
}
Output
Thread 1 : Learn Java
Thread 2 : Learn Java
Thread 2 : Coding in Python
Thread 1 : Coding in Python
Thread 2 : Data Structures
Thread 1 : Data Structures
Thread 2 : Introduction to Database
Thread 1 : Introduction to Database
As we can see from the output, both threads are iterating ArrayList in parallelly because of the CopyOnWriteArrayList iterator is synchronized among the threads. Also, if any other thread made some modifications to the same CopyOnWriteArrayList, it will not appear in the iterator because to perform any modification, a new fresh copy of the underlying array has been created.

Related Posts:


Comments