Fail-Safe Iterator vs Fail-Fast Iterator

1. Einleitung

In diesem Artikel stellen wir das Konzept der ausfallsicheren und ausfallsicheren Iteratoren vor .

Fail-Fast-Systeme brechen den Betrieb so schnell wie möglich ab, wodurch Fehler sofort aufgedeckt und der gesamte Betrieb gestoppt werden.

Während, Fail-Safe - Systeme nicht Abbruch einer Operation im Fall eines Ausfalls. Solche Systeme versuchen, Fehler so weit wie möglich zu vermeiden.

2. Fail-Fast- Iteratoren

Fail-Fast-Iteratoren in Java spielen nicht mit, wenn die zugrunde liegende Sammlung geändert wird.

Sammlungen verwalten einen internen Zähler namens modCount . Jedes Mal, wenn ein Element zur Sammlung hinzugefügt oder daraus entfernt wird , wird dieser Zähler erhöht.

Bei der Iteration wird bei jedem nächsten () Aufruf der aktuelle Wert von modCount mit dem Anfangswert verglichen. Wenn eine Nichtübereinstimmung vorliegt, wird eine ConcurrentModificationException ausgelöst, die den gesamten Vorgang abbricht.

Standarditeratoren für Sammlungen aus dem Paket java.util wie ArrayList , HashMap usw. sind Fail-Fast.

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

Im obigen Code-Snippet wird die ConcurrentModificationException zu Beginn eines nächsten Iterationszyklus ausgelöst, nachdem die Änderung durchgeführt wurde.

Das Fail-Fast-Verhalten kann nicht in allen Szenarien garantiert werden, da es bei gleichzeitigen Änderungen nicht möglich ist, das Verhalten vorherzusagen. Diese Iteratoren lösen ConcurrentModificationException nach besten Kräften aus .

Wenn während der Iteration über eine Sammlung , wird ein Element mit entfernt Iterator ‚s remove () Methode, die völlig sicher ist und keine Ausnahme werfen .

Wenn jedoch die Sammlung ‚s remove () Verfahren zum Entfernen eines Elements verwendet wird, führt es eine Ausnahme:

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. Ausfallsichere Iteratoren

Ausfallsichere Iteratoren bevorzugen das Fehlen von Fehlern gegenüber der Unannehmlichkeit der Ausnahmebehandlung.

Diese Iteratoren erstellen einen Klon der tatsächlichen Sammlung und iterieren darüber. Wenn nach dem Erstellen des Iterators Änderungen vorgenommen werden, bleibt die Kopie weiterhin unberührt. Daher durchlaufen diese Iteratoren weiterhin eine Schleife über die Sammlung, selbst wenn sie geändert wurde.

Es ist jedoch wichtig, sich daran zu erinnern, dass es keinen wirklich ausfallsicheren Iterator gibt. Der richtige Begriff ist schwach konsistent.

Das heißt, wenn eine Sammlung während der Iteration geändert wird, ist das, was der Iterator sieht, nur schwach garantiert . Dieses Verhalten kann für verschiedene Sammlungen unterschiedlich sein und ist in Javadocs jeder dieser Sammlungen dokumentiert .

Die ausfallsicheren Iteratoren haben jedoch einige Nachteile. Ein Nachteil ist, dass der Iterator nicht garantiert aktualisierte Daten aus der Sammlung zurückgibt , da er auf dem Klon anstelle der eigentlichen Sammlung arbeitet .

Ein weiterer Nachteil ist der Aufwand für das Erstellen einer Kopie der Sammlung in Bezug auf Zeit und Speicher.

Iteratoren für Sammlungen aus dem Paket java.util.concurrent wie ConcurrentHashMap , CopyOnWriteArrayList usw. sind ausfallsicher .

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); }

Im obigen Code-Snippet verwenden wir Fail-Safe Iterator . Obwohl während der Iteration ein neues Element zur Sammlung hinzugefügt wird, wird daher keine Ausnahme ausgelöst.

Der Standarditeratordenn die ConcurrentHashMap ist schwach konsistent. Dies bedeutet, dass dieser Iterator gleichzeitige Änderungen tolerieren kann, Elemente durchläuft, wie sie zum Zeitpunkt der Erstellung des Iterators vorhanden waren, und möglicherweise Änderungen an der Sammlung nach der Erstellung des Iterators widerspiegelt (dies ist jedoch nicht garantiert) .

Daher wird im obigen Codefragment die Iteration fünfmal wiederholt, was bedeutet , dass das neu hinzugefügte Element zur Sammlung erkannt wird .

4. Fazit

In diesem Tutorial haben wir gesehen, was Fail-Safe- und Fail-Fast- Iteratoren bedeuten und wie diese in Java implementiert sind.

Der vollständige Code in diesem Artikel ist auf GitHub verfügbar.