1

これが私の問題です:

このデータ構造の が存在する間に が変更さjava.util.ConcurrentModificationExceptionれるため、このコードは をスローします。java-doc によると、このコンテナーはフェイルファスト イテレーターのみを提供します。Vector listenersIterator

その「ライブ」中に要素が削除された場合、無効にならない(フェイルファストではない)を提供する、またはJavaIteratorのような標準コンテナを乗り越える可能性はありますか?VectorListIteratorIterator

std::listC++の場合と同じように動作する必要があります。そこでは、現在のイテレータが削除されていても、イテレータは常に有効です。イテレータがリスト内の次の要素に設定されるよりも。

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

4 に答える 4

8

私の知る限り、その機能をデフォルトのCollection実装にさかのぼって追加する方法はありません(Iterable実際)。

しかし、反復中の同時変更に対する明確に定義された応答を持つことによって、そのような動作をサポートする実装があります。

その一例がCopyOnWriteList.

于 2010-03-01T18:44:32.050 に答える
6

リスナーの場合、java.util.concurrent.CopyOnWriteArrayList通常は書き込みよりも読み取りの方がはるかに多いため、使用を検討することができます。

于 2010-03-01T18:44:02.157 に答える
2

java.util.concurrent パッケージを見てください。必要なものがすべて見つかります。

于 2010-03-01T18:42:29.287 に答える
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();
}
于 2010-03-01T19:36:20.617 に答える