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

StackOverflow https://stackoverflow.com/questions/2358126

  •  23-09-2019
  •  | 
  •  

Вопрос

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

Этот фрагмент кода выдает 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);
    }
}
Это было полезно?

Решение

Насколько я знаю, нет никакого способа задним числом добавить эту возможность к любому значению по умолчанию 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();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top