Gibt es ein Java-Container bieten eine ausfallsichere Iterator
Frage
Hier ist mein Problem:
Dieses Stück Code wirft eine java.util.ConcurrentModificationException
, weil die Vector
listeners
geändert wird, während es eine Iterator
für diese Datenstruktur vorhanden ist.
Die Java-doc sagt, dass dieser Container bietet nur ein ausfall schnell Iterator.
Gibt es eine Möglichkeit, einen Iterator
über einen Standard-Container wie Vector
oder List
in Java zu bekommen, dass Angeboten mir ein Iterator
, die nicht ungültig bekommt (nicht ausfall schnell), wenn es ein Element während dieses Iterator
entfernt ist " Leben "?
Ich sollte das gleiche Verhalten wie die std::list
in C ++ haben. Dort wird der Iterator ist immer gültig, auch wenn der aktuelle Iterator entfernen ist. Als der Iterator auf das nächste Element in der Liste gesetzt wird.
public class ClientHandle {
private final Vector<ClientHandleListener> listeners = new Vector<ClientHandleListener>();
public synchronized void addListener(ClientHandleListener chl) {
listeners.add(chl);
}
public synchronized void removeListener(ClientHandleListener chl) {
listeners.remove(chl);
}
private void fireConnectionClosed() {
final ClientHandle c = this;
final Iterator<ClientHandleListener> it = listeners.iterator();
new Thread(){
@Override
public void run() {
while (it.hasNext()) {
it.next().connectionClosed(c); //FIXME the iterator gets modified
}
};
}.start();
}}
public class ClientHandlePool implements ClientHandleListener, TaskManagerListener {
/*...*/
public synchronized void removeClientHandle(ClientHandle ch) {
//here the listeners Vector from the ClientHandle gets modified
ch.removeListener(this);
ch.removeListener(currentListener);
clientHandles.remove(ch);
}
@Override
public void connectionClosed(ClientHandle ch) {
removeClientHandle(ch);
}
}
Lösung
Soweit ich weiß, gibt es keine Möglichkeit, rückwirkend diese Fähigkeit zu einer Standard Collection
Implementierung hinzufügen (Iterable
in der Tat).
Aber es gibt Implementierungen, die Unterstützung, die Art von Verhalten, indem gut definierte Reaktionen auf gleichzeitige Modifikation während Iterieren.
Ein Beispiel ist das CopyOnWriteList
.
Andere Tipps
Bei Zuhörer, könnte man denken, über die Verwendung von java.util.concurrent.CopyOnWriteArrayList
wie Sie haben in der Regel viel mehr liest als schreibt.
einen Blick auf java.util.concurrent Paket haben Sie alles finden, was Sie brauchen.
Ein fauler Weg, um eine schnelle, ausfallsichere Iterator zu erstellen: Nehmen Sie eine Kopie der Liste als Array während gesperrt und foreach () über die Anordnung während entriegelt ... Kann mit jeder Art von Liste erfolgen
private void fireConnectionClosed() {
final ClientHandle c = this;
final ClientHandleListener[] listenersArr;
synchronized(this) {
listenersArr=listeners.toArray(new ClientHandleListener[0]);
}
new Thread(){
@Override
public void run() {
for(ClientHandleListener listener : listenersArr )
listener.connectionClosed(c);
}
};
}.start();
}