两个迭代器的故事

当您查看最受欢迎的Java面试问题时,可能会遇到有关快速故障和故障安全迭代器的问题:

故障快速迭代器和故障安全迭代器之间有什么区别?

简化的答案是:

如果在迭代过程中修改了集合,则快速失败迭代器将引发ConcurrentModificationException ,但不会失败保护。

尽管这完全有道理,但不清楚访调员的故障安全含义。 对于迭代器,Java规范未定义此术语。 但是,有四种同时进行修改的策略。

并发修改

首先,让我们定义什么是并发修改。 例如,当我们有一个来自集合的活动迭代器并且对该集合进行了一些更改,但它们不是来自我们的迭代器时,会发生并发修改。 最明显的例子是当我们有多个线程时–一个线程正在迭代,第二个线程在同一集合中添加或删除元素。 但是,当我们在单线程环境中工作时,我们也可以获取ConcurrentModificationException

List<String> cities = new ArrayList<>();
cities.add(“Warsaw”);
cities.add(“Prague”);
cities.add(“Budapest”);
 
Iterator<String> cityIterator = cities.iterator();
cityIterator.next();
cities.remove(1);
cityIterator.next(); // throws ConcurrentModificationException

不及格

上面的代码段是快速失败迭代器的示例。 如您所见,一旦我们尝试从迭代器中获取第二个元素,就会引发ConcurrentModificationException 。 迭代器如何知道创建集合后是否对其进行了修改? 您可能在集合中有一个时间戳,例如lastModified 。 创建迭代器时,需要复制此字段并将其存储在迭代器对象中。 然后,无论何时调用next()方法, lastModified需要将集合中的lastModified与迭代器中的副本进行比较。 例如,可以在ArrayList实现中找到非常相似的方法。 有一个modCount实例变量,其中包含对列表进行的修改次数:

final void checkForComodification() {
   if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
}

值得一提的是,快速失败迭代器是在尽力而为的基础上工作的-无法保证如果存在并发修改,则会抛出ConcurrentModificationException ,因此我们不应该依赖该行为-而是应将其用于检测错误。 大多数非并行集合都提供快速失败的迭代器。

弱一致性

java.util.concurrent包中的大多数并发集合(例如ConcurrentHashMap和most Queues )都提供了弱一致性的迭代器。 文档中对它的含义进行了很好的解释:

  • 他们可能会与其他操作同时进行
  • 他们永远不会抛出ConcurrentModificationException
  • 它们被保证可以遍历在构造时已经存在的元素一次,并且可以(但不保证)反映出构造后的任何修改。

快照

在此策略中,迭代器从创建迭代器的那一刻起即与集合的状态相关联-我们的集合快照。 对初始集合所做的任何更改都会创建基础数据结构的新版本。 当然,我们的快照是不变的,因此它不反映在创建迭代器之后对集合所做的任何更改。 这是一种古老的好的写时复制(COW)技术。 它完全解决了并发修改问题,因此不会引发ConcurrentModificationException 。 此外,迭代器不支持元素更改操作。 写入时复制集合通常太昂贵而无法使用,但是如果突变发生的次数显着减少,遍历遍历次数可能是个好主意。 示例为CopyOnWriteArrayListCopyOnWriteArraySet

未定义

未定义的行为可以在传统集合中找到,例如VectorHashtables 。 它们都具有具有快速失败行为的标准迭代器,但是它们还公开了Enumeration接口的实现,该接口在定义并发修改时不定义行为。 您可能会看到某些项目被重复或跳过,甚至出现一些奇怪的异常。 最好不要玩这个野兽!

翻译自: https://www.javacodegeeks.com/2017/11/tale-two-iterators.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值