How to Prevent ConcurrentModificationException in Java Collections
The article explains why ConcurrentModificationException occurs when a Java collection is structurally modified during iteration, illustrates typical scenarios such as enhanced‑for loops and multithreaded access, and provides practical solutions including iterator.remove(), thread‑safe collections, synchronized blocks and iterating over copies.
1. What is ConcurrentModificationException?
When an iterator traverses a collection and the collection’s structure is altered (add, remove, or replace elements) outside the iterator’s own remove method, the JVM throws a ConcurrentModificationException. The iterator cannot detect the structural change, leading to the exception.
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
for (String s : list) {
if (s.equals("A")) {
list.remove(s); // Throws ConcurrentModificationException
}
}2. Common scenarios that trigger the exception
2.1 Modifying a collection inside an enhanced for‑loop
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
for (Integer number : numbers) {
if (number == 2) {
numbers.remove(number); // Throws ConcurrentModificationException
}
}2.2 Modifying a shared collection from multiple threads
List<String> sharedList = new ArrayList<>();
sharedList.add("A");
sharedList.add("B");
Runnable modifyTask = () -> {
for (String s : sharedList) {
if (s.equals("A")) {
sharedList.remove(s); // May throw ConcurrentModificationException
}
}
};
new Thread(modifyTask).start();
new Thread(modifyTask).start();2.3 Modifying a map while iterating over it
Map<Integer, String> map = new HashMap<>();
map.put(1, "A");
map.put(2, "B");
for (Map.Entry<Integer, String> entry : map.entrySet()) {
if (entry.getKey() == 1) {
map.remove(entry.getKey()); // Throws ConcurrentModificationException
}
}3. Strategies to avoid the exception
3.1 Use the iterator’s remove() method
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number == 2) {
iterator.remove(); // Safe removal using iterator
}
}3.2 Switch to concurrent collections from java.util.concurrent
For multithreaded environments, use thread‑safe alternatives such as CopyOnWriteArrayList or ConcurrentHashMap, which are designed to handle concurrent modifications without throwing the exception.
List<String> safeList = new CopyOnWriteArrayList<>();
safeList.add("A");
safeList.add("B");
for (String s : safeList) {
if (s.equals("A")) {
safeList.remove(s); // No ConcurrentModificationException
}
} ConcurrentMap<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "A");
map.put(2, "B");
map.forEach((key, value) -> {
if (key == 1) {
map.remove(key); // Safe removal in ConcurrentHashMap
}
});3.3 Use synchronized blocks for manual synchronization
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
synchronized (list) {
for (String s : list) {
if (s.equals("A")) {
list.remove(s); // Safe removal inside synchronized block
}
}
}3.4 Iterate over a copy of the collection
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
for (String s : new ArrayList<>(list)) {
if (s.equals("A")) {
list.remove(s); // Safe removal from the original list
}
}4. Conclusion
ConcurrentModificationExceptionis a common runtime issue when a Java collection is structurally modified during iteration. By using iterator‑based removal, adopting concurrent collections, applying explicit synchronization, or iterating over a snapshot, developers can reliably avoid this exception and ensure correct concurrent behavior.
JakartaEE China Community
JakartaEE China Community, official website: jakarta.ee/zh/community/china; gitee.com/jakarta-ee-china; space.bilibili.com/518946941; reply "Join group" to get QR code
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
