Nein, nein, NEIN!
In einzelnen Thread-Aufgaben brauchst du keinen Iterator zu verwenden, und erst recht kein CopyOnWriteArrayList (aufgrund der Leistungseinbußen).
Die Lösung ist viel einfacher: versuche, statt der for-each Schleife eine kanonische Schleife zu verwenden.
Laut den Eigentümern des Java-Copyrights (vor einigen Jahren Sun, jetzt Oracle) forEach-Schleifenanleitung verwendet sie einen Iterator, um durch die Sammlung zu gehen und verbirgt ihn nur, um den Code besser aussehen zu lassen. Aber leider, wie wir sehen können, hat es mehr Probleme als Gewinne produziert, sonst würde dieses Thema nicht aufkommen.
Zum Beispiel führt dieser Code zu einer java.util.ConcurrentModificationException, wenn er in die nächste Iteration auf einer modifizierten ArrayList eintritt:
// Sammlung verarbeiten
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
Aber der folgende Code funktioniert einwandfrei:
// Sammlung verarbeiten
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; // um das Überspringen des verschobenen Elements zu vermeiden
}
}
Versuche also, den Indexansatz für das Iterieren über Sammlungen zu verwenden und vermeide die for-each-Schleife, da sie nicht äquivalent sind! Die for-each-Schleife verwendet interne Iteratoren, die die Sammlungsmodifikation überprüfen und eine ConcurrentModificationException auslösen. Um dies zu bestätigen, werfen Sie einen genaueren Blick auf den gedruckten Stack-Trace, wenn Sie das erste Beispiel verwenden, das ich gepostet habe:
Ausnahme im Thread "main" java.util.ConcurrentModificationException
bei java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
bei java.util.AbstractList$Itr.next(AbstractList.java:343)
bei TestFail.main(TestFail.java:43)
Für Multithreading verwenden Sie entsprechende Mehrfachaufgabenansätze (wie das synchronized-Schlüsselwort).