Fail-Safe Iterator (java.util.concurrent - ConcurrentSkipListSet, CopyOnWriteArrayList, ConcurrentMap)
Fail-safe Iterator is “Weakly Consistent” and does not throw any exception if collection is modified structurally during the iteration. Such Iterator may work on clone of collection instead of original collection - such as in CopyOnWriteArrayList. While ConcurrentHashMap’s iterator returns the state of the hashtable at some point at or since the creation of iterator. Most collections under java.util.concurrent offer fail-safe Iterators to its users and that’s by Design. Fail safe collections should be preferred while writing multi-threaded applications to avoid concurrency related issues.
Fail Safe Iterator is guaranteed to list elements as they existed upon construction of Iterator, and may reflect any modifications subsequent to construction (without guarantee).
Fail-Fast Iterator (java.util package - ArrayList, HashMap, HashSet, TreeSet, etc)
Iterator fails as soon as it realizes that the structure of the underlying data structure has been modified since the iteration has begun. Structural changes means adding, removing any element from the collection, merely updating some value in the data structure does not count for the structural modifications. It is implemented by keeping a modification count and if iterating thread realizes the changes in modification count, it throws ConcurrentModificationException. Methods calls that throw this exception are next(), previous(), remove(), set(i, obj), add(obj). This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
Most collections in package java.util are fail-fast by Design. These are not meant for multi-threading/ structural modification while iteration. Collection.toString() method requires iteration over the elements of collection, so they may throw exception if some parallel thread modifies the underlying collection data at the same time. This may happen even while logging a collection in the logger/Sysytem.out.println()