My question is more conceptual, I have been looking for answers on this question but I am not understanding them. What is the difference and what do they mean in each case? Can you give examples? Thanks.
My question is more conceptual, I have been looking for answers on this question but I am not understanding them. What is the difference and what do they mean in each case? Can you give examples? Thanks.
The difference is the behavior that they have in front of the concurrent modification.
Before you start, keep in mind that the implementation of these behaviors depends on each class and is not common, so the following is in general terms:
Fail-fast is a behavior of the Iterator
of a collection. It implies that the Iterator
checks aggressively that the underlying collection has not been modified since it started to iterate , and in Java the ConcurrentModificacionException
.
Imagine you have two threads acting on a list. The first one is dedicated to reading it, and the second modifies it. If the Iterator
of the first one has fail-fast behavior, each time you call methods that advance the position of the Iterator
it is checked that the list has not been modified. In our example, the second thread has modified the list, so the exception will be thrown.
Fail-fast is implemented with a change counter . The collection has this counter and its value is passed to Iterator
. When you call the methods that advance the position, the Iterator
checks that the values of the counters do not differ. If they differ, the exception is thrown.
The non-concurrent collections of the JDK are an example of fail-fast although in the documentation of the classes that implement it is clearly specified that this behavior is not assured .
An example with ArrayList
:
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
Iterator<Integer> iterator = numbers.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
numbers.add(4); // Modificacion de la lista mientras se itera
}
Output:
1
Exception in thread "main" java.util.ConcurrentModificationException
at
java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
at SOE.Main.main(Main.java:12)
Fail-safe is another behavior of Iterator
. This behavior implies that the Iterator
is protected from concurrent modifications, and however much the underlying collection is modified, the iteration will not be affected and no exception will be thrown. .
In our example, the Iterator
of the first thread would not be affected by the modifications of the second thread and your program would continue running without exceptions.
This is a bit more complicated, because the fail-safe behavior does not appear in the Java documentation. The closest thing is the weak consistency . The way in which this is usually implemented is that the Iterator
operates on a copy of the underlying collection, created at the time of creation of Iterator
. In this way, all modifications made to the original collection will not affect your iteration.
Collections of java.util.concurrent
usually apply this behavior. An example with ConcurrentHashMap
:
ConcurrentMap<String,String> capitales = new ConcurrentHashMap<>();
capitales.put("España", "Madrid");
capitales.put("Francia", "Paris");
capitales.put("Alemania", "Berlin");
Iterator<String> iterator = capitales.keySet().iterator(); // Se crea una copia
while (iterator.hasNext()) {
System.out.println(capitales.get(iterator.next()));
capitales.put("Inglaterra", "Londres"); // Modificacion del map mientras se itera
}
And the output:
Paris
Madrid
Berlin
Interestingly, if you try to put as keys of a ConcurrentMap
integers, the modification is done. I suppose this has to do with the hashing and that the implementation of ConcurrentHashMap
allows the concurrent modification with certain types of keys.
In any case, this should serve as an example of what I put at the beginning: The implementations depend on each class and to know them in depth you should read the documentation and the source code.