Pergunta

Aqui está o meu problema:

Este pedaço de código joga um java.util.ConcurrentModificationException, porque o Vector listeners é modificado enquanto existe um Iterator Para esta estrutura de dados. O Java-Doc diz que esse contêiner oferece apenas um iterador de falha.

Existe a possibilidade de obter um Iterator sobre um contêiner padrão como Vector ou List em java que me oferece um Iterator, isso não é inválido (não é rápido), se houver um elemento removido durante isso Iterator "vidas"?

Eu deveria ter o mesmo comportamento como o std::list em C ++. Lá, o iterador é sempre válido, mesmo que o iterador atual seja removido. Do que o iterador está definido para o próximo elemento na lista.

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);
    }
}
Foi útil?

Solução

Tanto quanto eu sei, não há como retroativamente adicionar essa capacidade a qualquer padrão Collection implementação (Iterable na verdade).

Mas existem implementações que suportam esse tipo de comportamento, tendo respostas bem definidas à modificação simultânea enquanto itera.

Um exemplo é o CopyOnWriteList.

Outras dicas

Em caso de ouvintes, você pode pensar em usar java.util.concurrent.CopyOnWriteArrayList Como você normalmente tem muito mais leituras do que as gravações.

Dê uma olhada no pacote java.util.concurrent, você encontrará tudo o que precisa.

Uma maneira preguiçosa de criar um iterador rápido e seguro para falhas: pegue uma cópia da lista como uma matriz enquanto bloqueada e foreach () sobre a matriz enquanto desbloqueada ... pode ser feita com qualquer tipo de lista

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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top