2010-03-01 16 views
1

Вот моя проблема:ли контейнер 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); 
    } 
} 
+1

Ваша проблема заключается в использовании вектора для начала, не используйте Векторное использование списка, векторов и хэш-таблиц - это обычная практика и старые. См. Пакет java.util.concurrent. –

+2

@fuzzy: 'Vector' и' Hashtable' не обязательно плохие. Когда вам нужны их специфические функции (в основном синхронизация), тогда у них есть действующее место. –

+1

@joachim Ну, вот почему пакет java.util.concurrent, как уже говорилось, нечеткое. CopyOnWriteArrayList очень полезен, когда вам приходится иметь дело с одновременными изменениями. * edit *: Кроме того, существуют также методы java.util.Collections.synchronizedXYZ, которые в основном создают синхронизированную копию вашего списка/карты/набора/etc ... Вам все равно придется использовать синхронизированные блоки, хотя – Tedil

ответ

8

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

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

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

+0

+1: CopyOnWriteList - это то, что я собирался предложить. –

+0

+1 спасибо. который решил мою проблему – nutario

2

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

6

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

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^