Synchronized and Concurrent Collection
In Java, both synchronized collections and concurrent collections are used for managing access to shared data structures in a multithreaded environment, but they differ in their underlying mechanisms and intended use cases.
Table of Contents
1. Synchronized Collections
- Synchronized collections are wrappers around existing collections (e.g., ArrayList, HashMap) that provide thread-safe access by synchronizing all methods that modify the collection.
- Synchronized collections use intrinsic locks (mutexes) to enforce mutual exclusion, ensuring that only one thread can modify the collection at a time.
- While synchronized collections offer thread safety, they can suffer from performance overhead due to the need for acquiring and releasing locks, especially in scenarios with high contention.
- Synchronized collections are suitable for scenarios where the number of write operations is relatively low compared to read operations or when simpler synchronization mechanisms are sufficient.
2. Concurrent Collections
- Concurrent collections are specifically designed for concurrent access by multiple threads without the need for external synchronization.
- Concurrent collections use more sophisticated concurrency control mechanisms, such as lock striping, non-blocking algorithms, or optimistic concurrency control, to achieve high concurrency and scalability.
- Concurrent collections offer better performance and scalability in highly concurrent scenarios compared to synchronized collections, as they minimize contention and provide better support for read and write operations from multiple threads.
- Concurrent collections are suitable for high-concurrency scenarios where multiple threads frequently read and write to the collection concurrently.
Let’s demonstrate the difference between synchronized and concurrent collections in Java with an example:
Example
java
import java.util.*;
import java.util.concurrent.*;
public class CollectionExample {
public static void main(String[] args) {
// Synchronized List
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
// Concurrent List
List<Integer> concurrentList = new CopyOnWriteArrayList<>();
// Synchronized Map
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
// Concurrent Map
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// Synchronized Set
Set<Integer> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
// Concurrent Set
Set<Integer> concurrentSet = ConcurrentHashMap.newKeySet();
// Modify synchronized collection in multiple threads
Thread thread1 = new Thread(() -> {
synchronized (synchronizedList) {
synchronizedList.add(1);
}
synchronized (synchronizedMap) {
synchronizedMap.put("a", 1);
}
synchronized (synchronizedSet) {
synchronizedSet.add(1);
}
});
// Modify concurrent collection in multiple threads
Thread thread2 = new Thread(() -> {
concurrentList.add(2);
concurrentMap.put("b", 2);
concurrentSet.add(2);
});
thread1.start();
thread2.start();
// Wait for threads to finish
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Print contents of collections
System.out.println("Synchronized List: " + synchronizedList);
System.out.println("Concurrent List: " + concurrentList);
System.out.println("Synchronized Map: " + synchronizedMap);
System.out.println("Concurrent Map: " + concurrentMap);
System.out.println("Synchronized Set: " + synchronizedSet);
System.out.println("Concurrent Set: " + concurrentSet);
}
}
In this example, we compare synchronized and concurrent versions of lists, maps, and sets. We modify both synchronized and concurrent collections in multiple threads simultaneously. After the threads complete execution, we print the contents of each collection to observe the behavior of synchronized and concurrent collections under concurrent access.