ConcurrentModificationException in Java
ConcurrentModificationException
is a runtime exception in Java that arises when multiple threads try to modify a collection at the same time. In this blog, weβll explore what ConcurrentModificationException
is, the scenarios in which it occurs, and how to prevent it in Java programs.
1. What is ConcurrentModificationException?
ConcurrentModificationException
is an exception that occurs when you attempt to modify a collection (e.g., ArrayList
, HashMap
, HashSet
) while another thread is concurrently iterating over it. This exception indicates that the collectionβs structural modification and its iteration are not synchronized, leading to data inconsistencies and potential errors.
2. When ConcurrentModificationException Arises
1. Simultaneous Iteration and Modification: This exception occurs when one thread is iterating over a collection (e.g., using an Iterator
or enhanced for loop), and another thread tries to add, remove, or modify elements within the same collection.
List<String> names = new ArrayList<>();
names.add("Sagar");
names.add("Pradnya");
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Pradnya")) {
// Concurrent modification by another thread
names.remove(name);
}
}
2. Using Non-thread-safe Collections: ConcurrentModificationException
can also happen when you use non-thread-safe collections without proper synchronization. These collections are not designed for concurrent access and can lead to unpredictable behavior when multiple threads access them simultaneously.
3. Preventing ConcurrentModificationException
To prevent ConcurrentModificationException
and ensure safe concurrent access to collections, you can follow these strategies:
1. Use Thread-safe Collections: Whenever possible, use thread-safe collections provided by Javaβs java.util.concurrent
package. Classes like CopyOnWriteArrayList
, ConcurrentHashMap
, and ConcurrentLinkedQueue
are designed for concurrent access and modify their internal structures to prevent concurrent modification issues.
2. Synchronization: If you must use non-thread-safe collections, ensure proper synchronization by using synchronized blocks or methods to control access to the collection. This involves wrapping the collection modifications inside synchronized blocks.
List<String> names = new ArrayList<>();
names.add("Sagar");
names.add("Pradnya");
synchronized (names) {
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Pradnya")) {
iterator.remove(); // Safely remove elements
}
}
}
3. Use Iteratorβs Remove Method: If you need to remove elements from a collection while iterating over it, use the remove
method provided by the Iterator itself. This method ensures that the collection is modified in a way that is safe for concurrent access.
List<String> names = new ArrayList<>();
names.add("Sagar");
names.add("Pradnya");
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Pradnya")) {
iterator.remove(); // Safely remove elements using iterator
}
}
4. Immutable Collections: Consider using immutable collections where the data is read-only. Immutable collections cannot be modified once created, making them safe for concurrent access without the risk of ConcurrentModificationException
.
List<String> names = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList("Sagar", "Pradnya"))
);
5. Concurrency Control: If you have complex scenarios with concurrent data modification, consider using more advanced concurrency control mechanisms like locks, semaphores, or the java.util.concurrent
frameworkβs classes, such as ReentrantLock
.
Related Post: Java ReentrantLock Example
4. Summary
ConcurrentModificationException
is a common challenge in multi-threaded Java applications. By understanding its causes and following best practices, you can ensure that your code is resilient to concurrent modifications. Whether itβs using thread-safe collections, proper synchronization, or the Iteratorβs remove
method, there are various strategies to keep your Java programs free from this exception and maintain data integrity in concurrent environments.