通过多线程删除 java.util.Collection 元素
在多线程模块中,我不关心它是否是线程安全地写入java.util.Collection
(例如java.util.Set
)对象。它的作用是通过多个线程删除一些独立的元素,这些线程可能会同时对同一个元素执行删除操作。那么,会发生什么呢?该元素被删除,或者抛出任何异常?
科佳
In a multi-thread module, I don't care whether it is thread-safely writing over a java.util.Collection
(e.g. java.util.Set
) object. What it does is removing some independent elements by multiple threads, which may perform removal on the same element at the same time. Then, what happens? That element is removed, or any exception is thrown?
Kejia
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当您删除不同的对象时,甚至有可能引发 ConcurrentModificationException。这取决于您正在使用的 Set 的实现:remove() 方法可能会迭代该集合。或者更糟糕:它可能会修改一些其他内部变量并使集合处于不一致的状态而不抛出任何异常。
有一个非常简单的解决方案:
如果您想迭代它,您仍然需要注意,如 apidoc 中所述: http://download.oracle.com/javase/6/docs/api/java/util/Collections.html# synchronizedSet%28java.util.Set%29 但所有其他方法(包括删除)都很好。
It is even possible that an ConcurrentModificationException is thrown, when you remove different objects. That depends on the implementation of the Set you are using: The remove() method may iterate over the set. Or worse: It may modifies some other internal variables and leave the set in an inconsistent state without throwing any exception.
There is a really easy solution:
You still need to pay attention if you want to iterate over it, as described in the apidoc: http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#synchronizedSet%28java.util.Set%29 but all the other methods (including remove) are fine.
结果是不可预测的。
Set
的内部结构可能会处于不一致且无法使用的状态。The results are unpredictable. The internal structure of the
Set
may be left in an inconsistent and unusable state.如果幸运的话,会出现“ConcurrentModificationException”。若无则乱。要么使用 Collections.synchronized* 要么在其他对象上同步,不要这样做。
'ConcurrentModificationException' if you are lucky. Chaos if not. Either use Collections.synchronized* or synchronize on some other object, don't do this.
java.util.Set只是一个接口。该行为取决于 Set 接口的实现。您不能使用多个线程访问 HashSet,因为无法保证行为,但如果这样做可能会抛出 ConcurrentModificationException。
java.util.Set is only an interface. The behaviour depends on the implementation of the Set interface. You must not access a HashSet with multiple threads as the behaviour is not guaranteed, although it is likely to throw ConcurrentModificationException if you do this.
您可能不在乎,因为您认为如果您这样做,集合将保持其完整性。但它不会。
您需要
Collections.newSetFromMap(new ConcurrentHashMap());
或使用某种同步。移除并不是这里唯一的问题。如果您只使用 HashSet,您也可能会在 Set 中得到重复项,或者谁知道还会发生什么。给定一个旨在处理线程问题的正确 Set 实现,那么一个线程将删除该项目,而另一个线程将发现该项目不存在,这可以通过 Set 上的删除方法的返回值来确定。
请注意,如果您要迭代集合,并且在迭代期间删除元素,则必须使用一些外部同步。
You might not care, because you think that the Set would retain its integrity if you do something like that. But it won't.
You either need
Collections.newSetFromMap(new ConcurrentHashMap<E, Boolean>());
or to use some syncronization. Removal isn't the only problem here. You could also end up with duplicates in the Set or who knows what else if you just use a HashSet.Given a proper Set implementation designed to handle threading issues, then one thread will remove the item and the other will find the item not there, which can be determined by the return value of the remove method on the Set.
Note that if you are iterating over the set, you have to use some external synchronization if you are removing elements during the iteration.