Предлагает ли контейнер Java отказоустойчивый итератор - PullRequest
1 голос
/ 01 марта 2010

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

Этот фрагмент кода выдает java.util.ConcurrentModificationException, потому что Vector listeners изменяется, пока существует 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 ]

8 голосов
/ 01 марта 2010

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

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

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

6 голосов
/ 01 марта 2010

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

2 голосов
/ 01 марта 2010

взгляните на пакет java.util.concurrent, вы найдете все необходимое.

0 голосов
/ 01 марта 2010

Ленивый способ создания быстрого и безотказного итератора: взять копию списка в виде массива, когда он заблокирован, и 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();
}
...