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);
    }
}
War es hilfreich?

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();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top