Question

Voici mon problème:

Ce morceau de code jette un java.util.ConcurrentModificationException, parce que le Vector de listeners est modifié alors qu'il existe un Iterator pour cette structure de données. Le java-doc dit que ce conteneur offre seulement un iterator fail-rapide.

Est-il possible d'obtenir un Iterator sur un conteneur standard comme Vector ou List en Java qui me propose un Iterator, qui ne reçoit pas invalide (est fail-rapide non), s'il y a un élément enlevé pendant cette Iterator " vit "?

Je devrais avoir le même comportement comme le std::list en C ++. Là, le iterator est toujours valable même si l'itérateur est de retirer en cours. Que le iterator est fixé à l'élément suivant dans la liste.

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);
    }
}
Était-ce utile?

La solution

Pour autant que je sais qu'il n'y a aucun moyen d'ajouter rétroactivement cette capacité à toute mise en œuvre de Collection par défaut (Iterable en fait).

Mais il y a des implémentations qui soutiennent ce genre de comportement en ayant des réponses bien définies à des modifications concurrentes tout en réitérant.

Un exemple est CopyOnWriteList .

Autres conseils

Dans le cas des auditeurs, vous pourriez penser à utiliser java.util.concurrent.CopyOnWriteArrayList que vous avez généralement beaucoup plus lectures que l'écriture.

un coup d'oeil au paquet java.util.concurrent vous trouverez tout ce dont vous avez besoin.

Une façon paresseuse pour créer un itérateur rapide, fail-safe: prendre une copie de la liste comme un tableau tout verrouillé, et foreach () sur le réseau tout débloqué ... Peut être fait avec tout type de liste

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();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top