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.