我有一个由许多线程不断扩展的Set:
Set<String> concurrentSet = new CopyOnWriteArraySet<>();
在某些时候我处理集合的元素,因为我不再需要处理过的元素,我使用iterator.remove()删除它们:
Iterator<String> i = concurrentSet .iterator();
while (i.hasNext()) {
String str = i.next();
//processing...
i.remove();
}
这线程安全吗?如果一个线程在迭代时添加元素怎么办?
注意:doc表示“如果在迭代正在进行的过程中修改基础集合而不是通过调用此方法,则未指定迭代器的行为。” =&GT;这对CopyOnWriteArraySet也是如此吗?
答案 0 :(得分:0)
我认为这适用于集合不是线程安全的情况。 ConcurrentHashset旨在被添加来处理这种情况..
答案 1 :(得分:0)
这取决于您使用的线程安全实现。例如:
CopyOnWriteArraySet
javadoc声明:“迭代器不支持变异删除操作。”=&gt;如果致电it.remove()
,您将收到例外情况。ConcurrenSkipListSet
javadoc声明:“插入,删除和访问操作由多个线程安全地同时执行。迭代器是弱一致的,返回元素反映集合的某个时刻或创建时的状态迭代器。“=&gt;你可以放心地假设调用it.remove()
是线程安全的(因为它不会抛出ConcurrentModificationException)。但请注意:
if (it.hasNext()) {
it.next();
it.remove();
}
不是原子的,因此如果同时修改该集合,则该操作的结果可能是意外的。
答案 2 :(得分:0)
CopyOnWriteArraySet
是线程安全的但是Iterators
不支持mutative remove操作,你可以使用CopyOnWriteArraySet#remove
删除ovject但是对这个数据结构的操作是昂贵的,因为所有的mutiable操作(添加由于此操作完全复制整个底层阵列,因此设置,删除等都很昂贵。
答案 3 :(得分:0)
来自Java 7 JavaDoc(http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArraySet.html):
[CopyOnWriteArraySet]迭代器不支持mutative remove操作。
如果线程安全性如果比性能更重要,我建议使用Collections.synchronizedSet这样的东西。它更难使用,你必须使用同步(set){}块中的迭代器显式包装代码,但是你可以保证所有操作都是线程安全的。
如果需要同时并发和线程安全,那么您可以通过ReentrantReadWriteLock使用正常的HashSet和您自己的显式锁定。如果正确实现,这将允许读并发和写线程安全。我不知道Java API中的标准类,但可能有一个(或者其他地方,例如Apache Commons Collections)。