Itérateur à sécurité intégrée vs itérateur à échec rapide

1. Introduction

Dans cet article, nous présenterons le concept d' itérateurs Fail-Fast et Fail-Safe .

Les systèmes Fail-Fast interrompent l'opération aussi vite que possible, exposant immédiatement les pannes et arrêtant l'ensemble de l'opération.

Alors que les systèmes Fail-Safe n'interrompent pas une opération en cas de panne. De tels systèmes essaient d'éviter autant que possible les échecs.

2. Fail-rapide itérateurs

Les itérateurs rapides en Java ne fonctionnent pas lorsque la collection sous-jacente est modifiée.

Les collections gèrent un compteur interne appelé modCount . Chaque fois qu'un élément est ajouté ou supprimé de la collection , ce compteur est incrémenté.

Lors de l'itération, à chaque appel next () , la valeur actuelle de modCount est comparée à la valeur initiale. En cas de non-concordance, il lève l' exception ConcurrentModificationException qui annule toute l'opération.

Les itérateurs par défaut pour les collections du package java.util tels que ArrayList , HashMap , etc. sont Fail-Fast.

ArrayList numbers = // ... Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { Integer number = iterator.next(); numbers.add(50); }

Dans l'extrait de code ci-dessus, l' exception ConcurrentModificationException est levée au début d'un cycle d'itération suivant une fois la modification effectuée.

Le comportement Fail-Fast n'est pas garanti dans tous les scénarios car il est impossible de prédire le comportement en cas de modifications simultanées. Ces itérateurs lancent une exception ConcurrentModificationException au mieux .

Si lors de l' itération sur une collection , un élément est supprimé à l' aide Iterator de supprimer () méthode, qui est tout à fait sûr et ne jette pas une exception .

Cependant, si la Collection de » l'remove () méthode est utilisée pour retirer un élément, il déclenche une exception:

ArrayList numbers = // ... Iterator iterator = numbers.iterator(); while (iterator.hasNext()) { if (iterator.next() == 30) { iterator.remove(); // ok! } } iterator = numbers.iterator(); while (iterator.hasNext()) { if (iterator.next() == 40) { numbers.remove(2); // exception } }

3. Itérateurs à sécurité intégrée

Les itérateurs Fail-Safe préfèrent l'absence de pannes aux inconvénients de la gestion des exceptions.

Ces itérateurs créent un clone de la collection actuelle et l'itèrent. Si une modification se produit après la création de l'itérateur, la copie reste intacte. Par conséquent, ces itérateurs continuent de boucler sur la collection même si elle est modifiée.

Cependant, il est important de se rappeler qu'il n'y a pas d'itérateur véritablement Fail-Safe. Le terme correct est faiblement cohérent.

Cela signifie que si une collection est modifiée lors de l'itération, ce que voit l' itérateur est faiblement garanti . Ce comportement peut être différent pour différentes collections et est documenté dans les Javadocs de chacune de ces collections .

Les itérateurs à sécurité intégrée présentent cependant quelques inconvénients. Un inconvénient est que l' itérateur n'est pas garanti de renvoyer les données mises à jour de la collection , car il fonctionne sur le clone au lieu de la collection réelle .

Un autre inconvénient est la surcharge de création d'une copie de la collection , à la fois en termes de temps et de mémoire.

Les itérateurs sur les collections du package java.util.concurrent tels que ConcurrentHashMap , CopyOnWriteArrayList , etc. sont de nature à sécurité intégrée .

ConcurrentHashMap map = new ConcurrentHashMap(); map.put("First", 10); map.put("Second", 20); map.put("Third", 30); map.put("Fourth", 40); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); map.put("Fifth", 50); }

Dans l'extrait de code ci-dessus, nous utilisons Fail-Safe Iterator . Par conséquent, même si un nouvel élément est ajouté à la collection pendant l'itération, il ne lève pas d'exception.

L'itérateur par défautpour ConcurrentHashMap est faiblement cohérent. Cela signifie que cet Iterator peut tolérer des modifications concurrentes, parcourt les éléments tels qu'ils existaient lors de la construction d' Iterator et peut (mais n'est pas garanti) refléter les modifications apportées à la Collection après la construction de l' itérateur .

Par conséquent, dans l'extrait de code ci-dessus, l'itération boucle cinq fois, ce qui signifie qu'elle détecte l'élément nouvellement ajouté à la collection .

4. Conclusion

Dans ce didacticiel, nous avons vu ce que signifient les itérateurs Fail-Safe et Fail-Fast et comment ils sont implémentés en Java.

Le code complet présenté dans cet article est disponible à l'adresse over sur GitHub.