Fail-fast iterator iterates over collection. If collection gets modified while iterating, we get exception. Opposite applies for fail-safe, where iteration is happening on one collection, while write operation happen on copy of it, thus it is how fail-safe works (f.e. CopyOnWriteArrayList).
Can someone explain me how does ConcurrentSkipListSet has fail-safe? There are no copies when modifying collection (like CopyOnWrite classes do), so how does it happen? I read because its Iterator is weakly consistent. I read docs, I still don't understand. (but I do know what code visibility or happens-before relation in concurrency is).
Does anyone have logic and easy to remember explanation, as I am a beginner?
//Example:
ConcurrentSkipListSet<Integer> set = new ConcurrentSkipListSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
set.remove(4);
}
OUTPUT:
1
2
3
I was expecting ConcurrentException to be thrown here.. Please help :(
The "weakly consistent" term is defined in the java.util.concurrent package description:
Most concurrent Collection implementations (including most Queues) also differ from the usual java.util conventions in that their Iterators and Spliterators provide weakly consistent rather than fast-fail traversal:
- they may proceed concurrently with other operations
- they will never throw
ConcurrentModificationException
- they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.
In this case with ConcurrentSkipListSet
, the iterator does not have a "fast-fail" property, instead it reflects the modification of 4
having been removed from the set.
Internally, ConcurrentSkipListSet
is implemented with ConcurrentSkipListMap
, and its iterators are implemented by keeping track of which skip list node should be traversed next. This naturally gives you the "weakly consistent" property: If the next item is deleted, the iterator will still return it. If items beyond the next are deleted, the iterator will reflect those changes.