What is fail-fast vs fail-safe? — Cracked Java
// Java Collections Framework · Iterator, ListIterator, Iterable, Spliterator
MidTheory

What is fail-fast vs fail-safe?

Fail-fast iterators throw ConcurrentModificationException (CME) as soon as they detect structural modification during iteration. Fail-safe iterators tolerate concurrent modification by either iterating a snapshot or being weakly consistent.

Fail-fast

Most JDK collections — ArrayList, LinkedList, HashMap, HashSet, TreeMap — produce fail-fast iterators. They track a modCount and throw CME if any structural change is detected between iterator construction and the next operation.

List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
for (Integer i : list) {
    if (i == 2) list.remove(i);   // CME on next iteration
}

The fix is iterator.remove() or list.removeIf(...).

Fail-safe

Two flavors:

SnapshotCopyOnWriteArrayList, CopyOnWriteArraySet. The iterator holds a reference to the backing array at the moment it was created. All mutations replace the array; the iterator keeps reading the old one. Cost: every write copies the array.

List<String> log = new CopyOnWriteArrayList<>(List.of("a", "b"));
Iterator<String> it = log.iterator();
log.add("c");                       // safe
while (it.hasNext()) System.out.println(it.next()); // a, b — NOT c

Weakly consistentConcurrentHashMap, ConcurrentSkipListMap, ConcurrentLinkedQueue. The iterator:

  • Never throws CME.
  • Reflects state at some point at or after iterator construction.
  • May see modifications made after construction (may, not will).
  • Is guaranteed not to traverse an element twice.

Comparison

PropertyFail-fastSnapshot (COW)Weakly consistent
Throws CMEyes (best-effort)nono
Sees concurrent writesno — explodesno — frozen viewmaybe
Memory costlowfull copy per writelow
Thread-safe?noyesyes

Best-effort, not a guarantee

When to pick which

  • Single-threaded mutation during iteration → use Iterator.remove() or removeIf().
  • Many readers, few writers → CopyOnWriteArrayList.
  • Concurrent map access → ConcurrentHashMap.
  • Need atomicity across reads? → external lock or compute/merge.

Mark your status