Java中的故障安全和故障快速迭代器
Java中有两种types的迭代器:失效保护和失效快速。
这是什么意思,是他们之间的区别?
他们之间有什么区别…
“故障安全”意味着:它不会失败。 严格地说,在Java中没有这样的事情作为故障安全迭代器。 正确的术语是“弱一致”。 javadoc说:
“大多数并发集合实现(包括大多数队列)也不同于通常的java.util惯例,因为它们的迭代器和Spliterator提供了弱一致性而不是快速失败遍历。
通常,弱一致性意味着如果一个集合与一个迭代同时被修改,那么迭代看到的保证就会变弱。 (细节将在每个并发集合类javadocs中指定。
“快速失败”是指: 可能会失败…并积极检查故障条件,以便在可以完成损坏之前检测到故障条件(在可能的情况下1 )。 在Java中,通过抛出ConcurrentModificationException
exception快速迭代器失败。
“快速失败”和“弱一致”的替代方法是迭代失败的语义; 例如,有时会给出错误的答案或抛出一个完全意想不到的例外。 (这是Java早期版本中Enumeration
API的一些标准实现的行为。)
…和它们与我们用于收集的迭代器不同。
不,这些是由标准集合types实现的迭代器的属性 ; 即它们要么是“快速失败”,要么是“弱一致”…在正确使用同步和Java内存模型1时 。
通常在集合对象上使用volatile
计数器来实现失效快速迭代器。
- 收集更新时,计数器递增。
- 当一个
Iterator
被创build时,计数器的当前值被embedded在Iterator
对象中。 - 当
Iterator
操作被执行时,该方法比较两个计数器值,并且如果它们不同则抛出CME。
故障安全迭代器的实现通常是轻量级的。 它们通常依赖于特定列表实现的数据结构的属性。 没有一般的模式。 (阅读您感兴趣的特定集合类的源代码。)
1 – 骑车者认为,快速行为假定应用程序ID在同步和内存模型方面正确。 这意味着(例如)如果您迭代ArrayList
没有正确的同步,最终的结果可能是一个损坏的列表结果。 “快速失败”机制可能会检测到并发修改(虽然这不是保证),但它不会检测到底层的损坏。 作为一个例子, Vector.iterator()
javadoc说:
“迭代器的快速失败行为不能保证,一般来说,不可能在存在非同步并发修改的情况下做出任何硬性保证,快速失败的迭代器会尽可能抛出
ConcurrentModificationException
,因此它会编写一个依赖于这个exception的程序是错误的,因为它的正确性:迭代器的快速失败行为应该只被用来检测错误。
他们是相当快速和弱一致的types:
java.util
迭代器抛出ConcurrentModificationException
如果集合的方法修改了集合的方法(add / remove),而迭代
java.util.concurrent
包中的迭代器通常在快照上迭代并允许并发修改,但是在创build迭代器后可能不会反映集合更新。
唯一的区别是自动防故障迭代器不会抛出任何exception,这与快速迭代器相反。
如果集合在结构上被修改,而一个线程正在迭代它。 这是因为他们对Collection的clone而不是原始的collection,所以他们被称为fail-safe迭代器。
CopyOnWriteArrayList的迭代器是故障安全迭代器的一个例子,ConcurrentHashMap写的迭代器keySet也是故障安全迭代器,永远不会抛出Java中的ConcurrentModificationExceptionexception。