1

这是我的问题:

这段代码抛出一个java.util.ConcurrentModificationException,因为这个数据结构Vector listeners存在一个 被修改。Iteratorjava-doc 说这个容器只提供了一个快速失败的迭代器。

如果在“生命”期间删除了一个元素,是否有可能Iterator通过标准容器(如JavaVectorListJava)为我提供一个Iterator不会变得无效(不是快速失败)的容器Iterator

我应该具有与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()... 可以使用任何类型的 List

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 回答