skip to content

Contrast fail-fast and fail-safe (weakly consistent) iterators, and give examples of collections that use each.

level: seniorimportance: should knowfreq 58%

answer

  1. fail-fast = throws CME (ArrayList/HashMap)
  2. weakly consistent = never throws (ConcurrentHashMap)
  3. snapshot/COW = frozen array (CopyOnWriteArrayList)
  4. 'fail-safe' is colloquial for weakly-consistent/snapshot
  5. safe ≠ fresh/consistent

basics

~20 s

Fail-fast iterators (like ArrayList's and HashMap's) throw an error if the collection changes during iteration. Fail-safe iterators (like ConcurrentHashMap's or CopyOnWriteArrayList's) don't throw — they work over a snapshot or tolerate changes, but may not show the very latest updates.

solid answer

~50 s

Fail-fast iterators detect structural modification via a modCount check and throw ConcurrentModificationException immediately — used by the non-concurrent collections (ArrayList, LinkedList, HashMap, HashSet, TreeMap). They're optimized for the common case where the collection isn't shared, and act as a bug detector. Fail-safe iterators — more precisely weakly consistent — never throw CME; they're used by concurrent collections. ConcurrentHashMap and ConcurrentLinkedQueue have weakly-consistent iterators that traverse elements as they existed at or after iterator creation and may reflect some later changes but with no consistency guarantee. CopyOnWriteArrayList/Set iterate an immutable snapshot taken at construction, so they never throw and never see later writes (and their iterator.remove() is unsupported). The trade-off: fail-safe gives you safe concurrent traversal but possibly stale data and extra memory/copy cost; fail-fast gives you fresh data and cheap iteration but no thread-safety and loud failure on misuse.

go deeper

for a junior

Knows the headline: regular collections throw on modification during iteration; concurrent ones (ConcurrentHashMap, CopyOnWriteArrayList) don't.

for a middle

Can list which collections are fail-fast vs concurrent and state that concurrent iterators never throw CME but may not reflect the latest changes.

for a senior

Distinguishes weakly-consistent (CHM) from snapshot/COW semantics, knows COW iterator.remove is unsupported, and explains the freshness-vs-cost trade-offs to pick the right structure.

for a principal

Drives data-structure selection by access pattern and contention profile, reasons about COW's O(n)-per-write cost and weakly-consistent visibility guarantees, and codifies team conventions for shared mutable state.

## Two strategies for 'what happens if the collection changes while I'm iterating it' When you walk a collection with an iterator and the collection is modified mid-walk, a library must choose a policy. Java's collections fall into two families. ### 1. Fail-fast iterators **Definition:** an iterator that throws `ConcurrentModificationException` (CME) as soon as it detects the backing collection was **structurally modified** (size changed) after the iterator was created — except through the iterator's own `remove`/`add`. **How:** via the `modCount` / `expectedModCount` comparison (see the modCount question). Cheap, unsynchronized, **best-effort**. **Who uses it:** the standard, non-thread-safe collections — `ArrayList`, `LinkedList`, `Vector`'s iterator (though Vector's *methods* are synchronized, its iterator is still fail-fast), `HashMap`, `LinkedHashMap`, `HashSet`, `TreeMap`, `TreeSet`. **Pros:** surfaces misuse loudly and immediately; zero copying; always sees the freshest data; iteration is fast. **Cons:** unusable for concurrent traversal; the detection is not a real concurrency guarantee. ### 2. Fail-safe / weakly consistent iterators The term **'fail-safe'** is colloquial; the JDK's precise terms are **weakly consistent** and **snapshot**. Both *never throw CME*. **(a) Weakly consistent** (`ConcurrentHashMap`, `ConcurrentSkipListMap`, `ConcurrentLinkedQueue`, `ConcurrentSkipListSet`). The contract: - It will traverse elements as they existed upon construction of the iterator, and **may** (but is not guaranteed to) reflect modifications made after construction. - It **never throws** `ConcurrentModificationException`. - It supports concurrent modification by other threads without corrupting the traversal. - It does **not** give a point-in-time consistent snapshot — you might see some recent additions and miss others. **(b) Snapshot / copy-on-write** (`CopyOnWriteArrayList`, `CopyOnWriteArraySet`). Every mutating operation copies the entire backing array. The iterator binds to the array reference that existed **at iterator creation**, so: - It iterates a fully **immutable snapshot** — later writes are completely invisible to it. - It **never throws** CME. - `iterator.remove()`/`add()`/`set()` are **unsupported** (throw `UnsupportedOperationException`) — you can't mutate through it because the array is shared and immutable. - Cost: O(n) copy on every write — great for read-heavy, write-rare data; terrible for write-heavy. ## Comparison table (conceptual) | Aspect | Fail-fast | Weakly consistent | Snapshot (COW) | |---|---|---|---| | Throws CME? | Yes | Never | Never | | Sees concurrent writes? | (would throw) | Maybe, no guarantee | Never (frozen at creation) | | Thread-safe iteration? | No | Yes | Yes | | iterator.remove()? | Yes | Yes (CHM) | No (unsupported) | | Cost | Cheap | Cheap | Copy-per-write | | Examples | ArrayList, HashMap | ConcurrentHashMap, ConcurrentLinkedQueue | CopyOnWriteArrayList | ## Why not just make everything fail-safe? Fail-safe iteration costs either weaker freshness guarantees (weakly consistent) or memory/copy overhead (COW). For the overwhelmingly common single-threaded case, fail-fast is faster and the CME is a *gift* — it catches a real bug at the point of misuse. The right answer is to pick the data structure for the access pattern: single-threaded or externally-synchronized → fail-fast collection; shared concurrent mutation → concurrent collection with its weakly-consistent iterator; read-mostly shared list → copy-on-write. ## Common misconception 'Fail-safe means it shows me the latest data safely.' No — *safe* here means *won't throw / won't corrupt*, **not** *consistent or up-to-date*. Weakly consistent iterators may show stale or partial views; COW shows a frozen snapshot.

  • Can you remove an element through a CopyOnWriteArrayList's iterator?
    No. Its iterator operates on an immutable snapshot, so remove(), set(), and add() throw UnsupportedOperationException. You must mutate through the list itself (which copies the backing array).
  • Does a ConcurrentHashMap iterator give you a consistent point-in-time view?
    No. It's weakly consistent: it traverses elements present at creation and may or may not reflect later modifications, with no guarantee. It never throws CME, but it is not a snapshot.

saying these in an interview costs you the question

  • Assuming 'fail-safe' means you always see the latest, consistent data — it only means it won't throw/corrupt.
  • Thinking CopyOnWriteArrayList's iterator supports remove()/set() — they throw UnsupportedOperationException.
  • Calling ConcurrentHashMap's iterator a point-in-time snapshot — it's weakly consistent, not a snapshot.
  • Claiming concurrent collections throw CME under modification — they never do.

context