Java容器是否提供故障安全迭代器

时间:2010-03-01 18:38:52

标签: java iterator fail-fast

这是我的问题:

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

是否有可能在Java中为IteratorVector标准容器List提供Iterator Iterator,而不会无效{是std::list如果在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); } } “生命”期间删除了一个元素?

我应该像C ++中的{{1}}一样行为。即使删除了当前的迭代器,迭代器也始终有效。比迭代器设置为列表中的下一个元素。

{{1}}

4 个答案:

答案 0 :(得分:8)

据我所知,没有办法追溯性地将该功能添加到任何默认的Collection实现中(Iterable实际上)。

但是有些实现通过在迭代时对并发修改做出明确定义的响应来支持这种行为。

一个例子是CopyOnWriteList

答案 1 :(得分:6)

如果是侦听器,您可能会考虑使用java.util.concurrent.CopyOnWriteArrayList,因为通常读取的次数多于写入次数。

答案 2 :(得分:2)

查看java.util.concurrent包,您将找到所需的一切。

答案 3 :(得分: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();
}