[Java] Erläutert die ConcurrentModificationException, die in java.util.ArrayList für Neulinge auftritt
Einführung
ConcurrentModificationException, die auch in einem einzelnen Thread auftritt
- Es ist eine bekannte Geschichte, dass "java.util.ConcurrentModificationException" auftritt, wenn eine nicht threadsichere "java.util.ArrayList" -Instanz von einem anderen Thread geändert wird, aber auch bei der Verarbeitung einzelner Threads. ..
- Ich wurde gebeten, dass ein solches Problem in verschiedenen Scheinprüfungen gestellt wird.
- Also, über "ConcurrentModificationException", die sogar in einem einzelnen Thread auftritt.
- Was den Inhalt betrifft, wird in den folgenden Fällen keine Ausnahme ausgelöst.
DenaiConcurrentModificationException.java
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
for (String str : list) {
if ("C".equals(str)) {
list.remove(str);
} else {
System.out.println(str);
}
}
}
- In diesem Fall wird "ConcurrentModificationException" ausgelöst.
DeruConcurrentModificationException.java
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
for (String str : list) {
if ("C".equals(str)) {
list.remove(str);
} else {
System.out.println(str);
}
}
}
Wann tritt eine ConcurrentModificationException auf?
- Wie man Fragen stellt, wird einer der oben genannten Codes beschrieben, und was wird das Ergebnis sein? Es werden die Inhalte wie.
- Der Gesichtspunkt ist, ob "ConcurrentModificationException" ausgelöst wird oder nicht. Wenn Sie das vorletzte oder letzte Element der Liste entfernen, wird es als grobe Testvorbereitung als "nicht erledigt" ausgegeben, andernfalls als "erledigt".
- Das ist nur das Obige, also schauen wir uns das Dokument und den Code an.
Java 8 SE ConcurrentModificationException-Dokumentation
Diese Ausnahme wird ausgelöst, wenn eine Methode, die eine parallele Änderung in einem Objekt erkennt, eine solche Änderung nicht zulässt.
Beispielsweise ist es im Allgemeinen nicht zulässig, dass ein anderer Thread die Sammlung ändert, während ein Thread die Sammlung durchläuft.
In einer solchen Umgebung sind die Ergebnisse der iterativen Verarbeitung normalerweise nicht garantiert.
Einige Iteratoren(Iterator)Implementierung von(JREが提供するすべての一般的な目的のコレクションImplementierung vonの、イテレータImplementierung vonを含む)Ist
Sie können diese Ausnahme auslösen, wenn dieses Verhalten erkannt wird.
Der Iterator, der diese Ausnahme auslöst, wird als ausfallsicherer Iterator bezeichnet.
Iteratoren lösen sofort und ordentlich Ausnahmen aus, um das Risiko unvorhersehbaren Verhaltens an unvorhersehbaren Punkten in der Zukunft zu vermeiden.
- Kurz gesagt, wenn während der iterativen Verarbeitung eine Änderung von einem anderen Thread erkannt wird, wird diese ausgelöst.
- Soll der "Failfast Iterator" im Text geschäftlich früh versagen? Dies bedeutet nicht, dass es sich um einen Iterator handelt, der sofort eine Ausnahme auslöst und die Verarbeitung unterbricht, wenn die Möglichkeit unerwarteter Änderungen besteht.
- Eine Ausnahme für einen einzelnen Thread wird hier nicht erwähnt, daher werde ich ihn etwas genauer lesen.
Diese Ausnahme bedeutet nicht unbedingt, dass das Objekt nicht parallel von einem anderen Thread aktualisiert wurde.
Das Objekt löst diese Ausnahme aus, wenn ein einzelner Thread eine Reihe von Methoden ausgibt, die gegen die Konventionen des Objekts verstoßen.
Wenn beispielsweise ein Thread eine Sammlung direkt ändert, während er mit einem ausfallsicheren Iterator über eine Sammlung iteriert.
Der Iterator löst diese Ausnahme aus.
- Erstens ist java.util.ArrayList ein ausfallsicherer Iterator.
Es scheint, dass immer eine "ConcurrentModificationException" ausgelöst wird, wenn ein Thread eine Sammlung direkt ändert, während er mit * iteriert.
- Aber manchmal passiert es nicht ... also schauen wir uns die Implementierung an.
Schauen Sie sich die Implementierung von java.util.ArrayList an
- Zuerst können Sie sehen, dass die erweiterte for-Schleife intern einen Iterator verwendet.
java
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {}
Mit * wird die ConcurrentModificationException ausgelöst, wenn bei jeder Bewegung des Cursors ein Unterschied zwischen expectedModCount und modCount besteht. Sie können die Rolle der Eigenschaft anhand des Namens erraten.
java
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
- Wenn Sie weiterlesen, können Sie sehen, dass
remove
modCount erhöht, was ConcurrentModificationException
verursacht.
java
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
- Wenn Sie sich auf System.arraycopy (elementData, index + 1, elementData, index, numMoved) konzentrieren, können Sie sehen, dass beim Löschen des C-Elements das folgende Element wie unten gezeigt nach oben verschoben wird.
- Wie in der obigen Abbildung gezeigt, wird das Element nach oben bewegt und der Cursor ändert sich nicht, sodass Element 3 nach "list.remove (" C ")" verarbeitet wird. Da 3 in der ersten Stufe nicht vorhanden ist, endet die Verarbeitung unverändert, die Verarbeitung wird in der zweiten Stufe fortgesetzt, "checkForComodification" wird ausgeführt und eine ConcurrentModificationException wird ausgelöst.
Zusammenfassung
- Ich habe es schwer mit Kopieren und Einfügen geschrieben, aber Sie können es verstehen, indem Sie sich die Implementierung und das Debuggen ansehen.
- Während des Qualifizierungskurses habe ich tatsächlich debuggt und die Antwort abgeleitet. ..