Fail-Fast Vs Fail-Safe Iterator in java
Last updated: September 2026 — rewritten with code examples, a comparison table, and interview Q&A.
Fail-fast vs fail-safe is a classic concurrency interview question — and a common tripwire. Most candidates can recite the definitions; few can explain why the distinction exists. It's also the doorway into deeper concurrency topics (BlockingQueue, CountDownLatch), so interviewers use it to decide how deep to dig.
What is fail-fast?
A fail-fast iterator works directly on the live collection. If the collection is structurally modified (add/remove) while iterating — by any means except the iterator's own remove() — it throws ConcurrentModificationException immediately:
List<String> langs = new ArrayList<>(Arrays.asList("Java", "Scala", "C++"));
Iterator<String> it = langs.iterator();
while (it.hasNext()) {
String lang = it.next();
if (lang.equalsIgnoreCase("java")) {
langs.remove(lang); // structural change OUTSIDE the iterator
}
}
// throws java.util.ConcurrentModificationException
The safe alternative is the iterator's own remove method:
while (it.hasNext()) {
if (it.next().equalsIgnoreCase("java")) {
it.remove(); // OK — no exception
}
}
Important nuance: fail-fast is best-effort, not guaranteed. Never write program logic that depends on the exception being thrown. (More in what fail-fast means, with examples.)
What is fail-safe?
A fail-safe iterator works on a snapshot copy of the collection, not the live one. Structural changes during iteration don't throw — but they also aren't visible to the iterator, and the snapshot costs extra memory:
List<String> langs = new CopyOnWriteArrayList<>(Arrays.asList("Java", "Scala", "C++"));
for (String lang : langs) {
if (lang.equalsIgnoreCase("java")) {
langs.remove(lang); // no exception — iterator sees the snapshot
}
}
System.out.println(langs); // [Scala, C++] — the removal DID happen
Fail-safe iterators are weakly consistent: they may or may not reflect modifications made after the iterator was created. Never assume you're seeing fresh data.
Fail-fast vs fail-safe: the differences
| Feature | Fail-fast | Fail-safe |
|---|---|---|
| Works on | The live collection | A snapshot copy |
| On structural modification | Throws ConcurrentModificationException | No exception |
| Memory overhead | None | Extra — maintains the copy |
| Sees concurrent changes? | N/A — it fails instead | Not guaranteed (weakly consistent) |
| Examples | ArrayList, HashMap, HashSet iterators | CopyOnWriteArrayList, ConcurrentHashMap iterators |
Interview rapid-fire
- Is fail-fast guaranteed to throw? — No. Best-effort only; the JVM makes no hard promise.
- How do you remove elements while iterating safely? — Use
iterator.remove(), or iterate aCopyOnWriteArrayList. - Why doesn't fail-safe see my update? — It iterates a snapshot taken when the iterator was created.
- Which concurrent collections are fail-safe? —
CopyOnWriteArrayList,ConcurrentHashMap,ConcurrentLinkedQueue. - Where does this lead in interviews? — Straight into the
java.util.concurrentpackage: blocking queues, latches, and lock granularity.
subodh excellent explanation keep it up. vikas
ReplyDeleteThanks Vikash,Keep visiting definitely, you will find something useful to you.
Delete