How to Create a Synchronized Collection in Java: A Step-by-Step Guide

How to Create a Synchronized Collection in Java: A Step-by-Step Guide

Introduction

Java collections are a fundamental part of the Java programming language. They allow for efficient data storage, retrieval, and manipulation. However, when working with multi-threaded applications, it’s essential to ensure thread safety when accessing or modifying shared collections. This is where synchronized collections come into play. In this guide, we’ll explore how to create synchronized collections in Java, the importance of thread safety, and practical code examples to help you implement synchronization in your own programs.

What are Synchronized Collections?

A synchronized collection in Java is a type of collection that ensures thread safety by allowing only one thread to access the collection at a time. This is particularly useful when multiple threads are trying to modify or access a shared collection simultaneously. Without proper synchronization, this can lead to inconsistent results, data corruption, or runtime errors.

Java provides several ways to create synchronized collections, either by using synchronized wrappers around existing collections or by leveraging concurrency-specific classes available in the java.util.concurrent package. Let’s explore these options.

Creating Synchronized Collections Using Collections.synchronizedXXX()

The Collections.synchronizedXXX() method is the easiest way to create synchronized versions of common collections. The Collections utility class provides synchronized wrappers for many of the standard collection classes, including List, Set, and Map. Here’s an example of how to use this method:

Example 1: Synchronized List


import java.util.*;

public class SynchronizedListExample {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("JavaScript");

        // Creating a synchronized list using Collections.synchronizedList()
        List synchronizedList = Collections.synchronizedList(list);

        synchronized (synchronizedList) {
            for (String language : synchronizedList) {
                System.out.println(language);
            }
        }
    }
}
        

In this example, we’ve created an ArrayList and then wrapped it in a synchronized list using Collections.synchronizedList(). We use the synchronized block to ensure thread safety when accessing the list.

Example 2: Synchronized Set


import java.util.*;

public class SynchronizedSetExample {
    public static void main(String[] args) {
        Set set = new HashSet<>();
        set.add("Apple");
        set.add("Banana");
        set.add("Orange");

        // Creating a synchronized set using Collections.synchronizedSet()
        Set synchronizedSet = Collections.synchronizedSet(set);

        synchronized (synchronizedSet) {
            for (String fruit : synchronizedSet) {
                System.out.println(fruit);
            }
        }
    }
}
        

This example demonstrates how to create a synchronized Set using the Collections.synchronizedSet() method. Again, we use a synchronized block to ensure thread safety while iterating through the set.

Example 3: Synchronized Map


import java.util.*;

public class SynchronizedMapExample {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("USA", "Washington D.C.");
        map.put("Canada", "Ottawa");
        map.put("India", "New Delhi");

        // Creating a synchronized map using Collections.synchronizedMap()
        Map synchronizedMap = Collections.synchronizedMap(map);

        synchronized (synchronizedMap) {
            for (Map.Entry entry : synchronizedMap.entrySet()) {
                System.out.println(entry.getKey() + ": " + entry.getValue());
            }
        }
    }
}
        

In this example, we’ve created a synchronized Map using Collections.synchronizedMap(). Just like the previous examples, we ensure thread safety by synchronizing the iteration over the map.

Using Concurrent Collections in Java

In addition to using synchronized wrappers, Java provides a set of thread-safe collections specifically designed for concurrent programming. These classes are part of the java.util.concurrent package and are often more efficient than using synchronized collections. Some commonly used concurrent collections are:

  • CopyOnWriteArrayList
  • CopyOnWriteArraySet
  • ConcurrentHashMap
  • BlockingQueue

Let’s explore an example of using a CopyOnWriteArrayList, which is a thread-safe variant of ArrayList.

Example 4: CopyOnWriteArrayList


import java.util.concurrent.*;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList list = new CopyOnWriteArrayList<>();
        list.add("Java");
        list.add("C++");
        list.add("Python");

        // Thread-safe iteration
        for (String language : list) {
            System.out.println(language);
        }
    }
}
        

The CopyOnWriteArrayList automatically handles synchronization for you, so you don’t need to manually synchronize blocks of code. This class is ideal when the collection is mostly read and occasionally updated, as it creates a copy of the underlying array for each modification.

Best Practices for Using Synchronized Collections

  • Use concurrent collections when possible: If you’re working in a multithreaded environment, consider using the classes from the java.util.concurrent package. They are designed for better performance and scalability compared to synchronized collections.
  • Minimize synchronized blocks: While using synchronized collections, try to minimize the time a thread spends inside a synchronized block. This reduces contention and improves performance.
  • Use locks for finer control: If you need more fine-grained control over synchronization, consider using explicit locks (e.g., ReentrantLock) instead of synchronized collections.
  • Understand your use case: Choose the right collection based on your application’s requirements. If your collection will be frequently modified, a concurrent collection like CopyOnWriteArrayList may be more suitable.

Conclusion

Synchronized collections are essential when dealing with multi-threaded applications in Java. By using synchronized wrappers or concurrent collections, you can ensure that your program handles concurrent access to shared data safely. Always consider the nature of your application and choose the appropriate approach to synchronization. With the examples provided in this guide, you’re now equipped to implement synchronized collections effectively in your Java programs.

© 2025 Tech Interview Guide. All Rights Reserved.

Please follow and like us:

Leave a Comment