【问题标题】:Does a Java container offer a fail-safe iteratorJava 容器是否提供故障安全迭代器
【发布时间】:2010-03-01 18:38:52
【问题描述】:

这是我的问题:

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

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

我应该具有与 C++ 中的 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);
    }
}

【问题讨论】:

  • 您的问题是使用 Vector 开始,不要使用 Vector 使用 List,Vectors 和 Hashtables 是不好的做法,而且陈旧。请参阅 java.util.concurrent 包。
  • @fuzzy: VectorHashtable 不一定是坏的。当您需要它们的特定功能(主要是同步)时,它们就有一个有效的位置。
  • @joachim 好吧,这就是为什么有 java.util.concurrent 包的原因,正如模糊已经说过的那样。当您必须处理并发修改时,CopyOnWriteArrayList 非常有用 - edit:除此之外,还有 java.util.Collections.synchronizedXYZ 方法,它们基本上创建了 List/Map 的同步副本/Set/etc...不过,您仍然必须使用同步块
  • 如果您需要线程安全的列表或映射,您可以使用线程安全的包装器。 Vector 和 Hashtable 已经过时了,在现代代码中看起来很糟糕。它们表明开发人员没有跟上时代和最佳实践的步伐。它们只是为了向后兼容。
  • @fuzzy:我知道还有其他选择,但究竟是什么让Vector 比使用Collections.synchronizedList() 包装的ArrayList 更糟糕?这里的“破坏”到底是什么意思?软件不会bitrot。如果您非常确定它们是为了向后兼容,那么我想知道为什么它们还没有被弃用。

标签: java iterator fail-fast


【解决方案1】:

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

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

一个例子是CopyOnWriteList

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      看看 java.util.concurrent 包你会找到你需要的一切。

      【讨论】:

        【解决方案4】:

        一种创建快速、故障安全迭代器的懒惰方法:在锁定时将列表的副本作为一个数组,并在解锁时对数组进行 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();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-26
          • 1970-01-01
          • 1970-01-01
          • 2015-12-17
          • 1970-01-01
          • 2016-11-15
          • 2015-04-27
          • 1970-01-01
          相关资源
          最近更新 更多