Q: Explain fail-fast vs fail-safe iterators. What is ConcurrentModificationException?
Answer:
Fail-Fast
Detect concurrent modification → throw ConcurrentModificationException immediately.
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
for (int x : list) {
if (x == 2) list.remove(Integer.valueOf(x)); // 💥 CME on next iteration
}
How it works: collection has modCount. Iterator captures expectedModCount at creation. On every next(), checks modCount == expectedModCount. Mismatch → CME.
// ArrayList.Itr#next()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
[!IMPORTANT] CME is not a guarantee — it's best-effort. Don't rely on it for thread safety. It's a debugging aid for incorrect single-threaded code.
Fail-Safe
Iterate over a snapshot or copy → no CME, but you may see stale data.
List<Integer> list = new CopyOnWriteArrayList<>(List.of(1, 2, 3));
for (int x : list) {
if (x == 2) list.remove(Integer.valueOf(x)); // ✅ no CME
// iterator sees the old snapshot — won't see the removal
}
Fail-Fast Collections
ArrayList,LinkedList,HashMap,HashSet,TreeMap,TreeSet,Vector(mostly),Hashtable(mostly).
Fail-Safe Collections
CopyOnWriteArrayList,CopyOnWriteArraySet— full snapshot on write.ConcurrentHashMap— weakly consistent iterator (sees some, not all, concurrent updates without CME).
Correct Removal During Iteration
// ❌ Wrong
for (String s : list) {
if (s.startsWith("x")) list.remove(s); // CME
}
// ✅ Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().startsWith("x")) it.remove();
}
// ✅ Java 8+
list.removeIf(s -> s.startsWith("x"));
Why iterator.remove() Works
It updates expectedModCount along with modCount. Other methods (list.remove()) bump modCount only.
Map Iteration Pitfall
Map<String, Integer> map = new HashMap<>();
for (var e : map.entrySet()) {
map.put("new", 1); // 💥 CME
}
Use:
map.entrySet().removeIf(e -> e.getValue() < 0);
// or replaceAll for value updates
map.replaceAll((k, v) -> v * 2);
Weakly Consistent (ConcurrentHashMap)
- No CME ever.
- Iterator may reflect updates after creation, may not.
- Safe across threads, but iteration is not a snapshot.