Предлагает ли контейнер Java отказоустойчивый итератор

Вот моя проблема:

Этот кусок кода бросает java.util.ConcurrentModificationException, поскольку Vectorlisteners модифицируется, пока существует Iterator для этой структуры данных. В документе java-doc говорится, что этот контейнер предлагает только быстрый итератор.

Есть ли возможность получить Iterator над стандартным контейнером, как Vector или же List в Java, который предлагает мне Iterator, который не становится недействительным (не сбой быстро), если во время этого элемента был удален Iterator "жизни"?

Я должен иметь такое же поведение, как std::list в C++. Там итератор всегда действителен, даже если текущий итератор удален. Затем для итератора устанавливается следующий элемент в списке.

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);
    }
}

4 ответа

Решение

Насколько я знаю, нет никакого способа задним числом добавить эту способность к любому значению по умолчанию. Collection реализация (Iterable по факту).

Но есть реализации, которые поддерживают такое поведение, имея четко определенные ответы на одновременную модификацию во время итерации.

Одним из примеров является CopyOnWriteList,

В случае слушателей, вы можете подумать об использовании java.util.concurrent.CopyOnWriteArrayList так как у вас обычно больше чтения, чем записи.

Посмотрите на пакет java.util.concurrent, вы найдете все, что вам нужно.

Ленивый способ создания быстрого и безотказного итератора: взять копию списка в виде массива, когда он заблокирован, и foreach() над массивом, когда он разблокирован... Может быть сделано с любым типом списка

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();
}
Другие вопросы по тегам