The author of the note is Grzegorz Mirek, a software developer from Krakow (Poland). He started developing in Java about 6 years ago, while still at university, and since that time he has been tirelessly polishing his skills in this area. He is particularly interested in JVM performance and optimization, which is what he mainly writes about on his blog .
Some of the most popular Java interview questions include: What is the difference between fail-fast and fail-safe iterators? The most simplified answer to this is: A fail-fast iterator throws a ConcurrentModificationException if the collection changes during iteration, but a fail-safe iterator does not. Although this sounds quite meaningful, it remains unclear what the interviewer means by fail-safe? The Java Language Specifications do not define this term in relation to iterators. However, there are four competitive modification strategies.
Competitive modification
First, let's define what competitive (or parallel) modification is. Let's say we have a collection and when the iterator is active, some changes occur that do not come from this iterator. In this case, we get a competitive modification. Let me give you a simple example: let's say we have several threads. The first thread iterates, and the second thread inserts or removes elements from the same collection. However, we can get a ConcurrentModificationException when running in a single-threaded environment:List<String> cities = new ArrayList<>();
cities.add(“Warsaw”);
cities.add(“Prague”);
cities.add(“Budapest”);
Iterator<String> cityIterator = cities.iterator();
cityIterator.next();
cities.remove(1);
cityIterator.next(); // генерирует ConcurrentModificationException
Fail-fast
The above code fragment is an example of a fail-fast iterator. As you can see, a ConcurrentModificationException was thrown when trying to retrieve the second element from the iterator . How does an iterator know that the collection has been modified since it was created? For example, the collection might have a date/time stamp, say lastModified . When creating an iterator, you should copy this field and store it in an iterator object. Then, each time the next() method is called , you will simply compare the lastModified value from the collection with the copy from the iterator. A very similar approach is used, for example, in the implementation of the ArrayList class . It has an instance variable modCount that stores the number of times the list has been modified:final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
It is important to note that fail-fast iterators operate on a best-of-breed basis, meaning that there is no guarantee that a ConcurrentModificationException will be thrown in the event of a concurrent modification. So you shouldn't rely on them - rather, they should be used to detect errors. Most non-concurrent collections provide fail-fast iterators.
Weak Consistency
Most concurrent collections in the java.util.concurrent package (such as ConcurrentHashMap and most Queue ) provide weakly consistent iterators. The meaning of this term is very well explained in the documentation :- They can be processed concurrently with other operations
- They never throw a ConcurrentModificationException
- They are guaranteed to traverse existing elements at the time the iterator was created exactly once, and can (but are not required to) reflect subsequent modifications.