【发布时间】:2010-03-01 18:38:52
【问题描述】:
这是我的问题:
这段代码抛出了一个java.util.ConcurrentModificationException,因为Vectorlisteners被修改了,而这个数据结构存在一个Iterator。
java-doc 说这个容器只提供了一个快速失败的迭代器。
是否有可能通过标准容器(如 Java 中的 Vector 或 List)获得 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:
Vector和Hashtable不一定是坏的。当您需要它们的特定功能(主要是同步)时,它们就有一个有效的位置。 -
@joachim 好吧,这就是为什么有 java.util.concurrent 包的原因,正如模糊已经说过的那样。当您必须处理并发修改时,CopyOnWriteArrayList 非常有用 - edit:除此之外,还有 java.util.Collections.synchronizedXYZ 方法,它们基本上创建了 List/Map 的同步副本/Set/etc...不过,您仍然必须使用同步块
-
如果您需要线程安全的列表或映射,您可以使用线程安全的包装器。 Vector 和 Hashtable 已经过时了,在现代代码中看起来很糟糕。它们表明开发人员没有跟上时代和最佳实践的步伐。它们只是为了向后兼容。
-
@fuzzy:我知道还有其他选择,但究竟是什么让
Vector比使用Collections.synchronizedList()包装的ArrayList更糟糕?这里的“破坏”到底是什么意思?软件不会bitrot。如果您非常确定它们是为了向后兼容,那么我想知道为什么它们还没有被弃用。