为了账号安全,请及时绑定邮箱和手机立即绑定

迭代器应该在源修改后什么时候抛出异常?

迭代器应该在源修改后什么时候抛出异常?

白猪掌柜的 2023-01-05 16:48:01
在下面的代码片段中,为 ArrayList 创建了一个迭代器,之后 ArrayList 的结构发生了变化。然后使用迭代器。ArrayList<Integer> list = new ArrayList<>(2);list.add(1);Iterator<Integer> itr = list.iterator();list.clear();list.add(2);list.add(3);while (itr.hasNext()) {    System.out.println(itr.next());}正如预期的那样, aConcurrentModificationException被抛出itr.next()。现在,看看这个:ArrayList<Integer> list = new ArrayList<>(2);list.add(1);int modCount = 1;Iterator<Integer> itr = list.iterator();do {    list.clear();    list.add(2);    list.add(3);    modCount += 3;} while (modCount != 1);while (itr.hasNext()) {    System.out.println(itr.next());}几秒后,执行结束,没有任何异常,结果为:23ArrayList 在结构上发生了变化,它的最终状态与第一个代码片段相同,但仍然没有抛出异常,即使在第一个代码片段中它抛出了异常。查看 ArrayList 源代码后,这是意料之中的,因为底层 modCount 是 int 类型。对 ArrayList 进行足够的修改会导致 modCount 溢出,在某个时候返回 1。Iterator 认为 ArrayList 没有改变,因此不会抛出异常。在 Java SE 12 文档中,对于 ArrayList 类,声明如下:请注意,无法保证迭代器的快速失败行为,因为一般来说,在存在非同步并发修改的情况下不可能做出任何硬性保证。很明显,迭代器可能会犯“错误”,但这又是针对非同步并发修改的,对吧?但是,上面的第二个片段是同步的。这里发生了什么?第二个片段中的 Iterator 应该是这样的吗?如果是这样,那么 long 类型的 modCount 会不会好一点(问题仍然不会消失,但是 2^64 + 1 修改在合理的时间内执行是不可行的)。这也可以在其他Collections 中观察到,它们使用相同的 int modCount 机制。
查看完整描述

3 回答

?
缥缈止盈

TA贡献2041条经验 获得超4个赞

Javadoc的下一句话:

Fail-fast 迭代器ConcurrentModificationException在尽力而为的基础上抛出。因此,编写依赖于此异常的正确性的程序是错误的:迭代器的快速失败行为应该仅用于检测错误

您只是很幸运(或者更确切地说,您正在构建一个非常精确的情况)您的代码不会抛出 CME。

我不会过多解读前一句关于“非同步并发修改”的强调。对此的一种迂腐的解读是,因为一件事可能发生,而这打破了保证,整个保证就被打破了,所以保证可能被打破的其他方式并不重要。


查看完整回答
反对 回复 2023-01-05
?
ITMISS

TA贡献1871条经验 获得超8个赞

您所做的一切都是创建一个场景,在该场景中,modCount 最终会环绕,直到它处于某种状态以反映没有发生修改,因此没有 CME。也许您希望 modCount 是 long 而不是 int。



查看完整回答
反对 回复 2023-01-05
?
潇湘沐

TA贡献1816条经验 获得超6个赞

稍加思索后,我得出结论:

  1. 如果 Iterator 抛出 a ConcurrentModificationException,则源在正在进行的迭代中进行了结构修改。

  2. 如果源在其迭代器处于正在进行的迭代中时在结构上被修改,则该迭代器可能会可能不会抛出ConcurrentModificationException.

考虑到这一点,迭代器尝试抛出 a 的唯一原因ConcurrentModificationException是帮助调试。总比没有好,尤其是在一般情况下。

在 modCount 中使用 long 而不是 int 将增加 may 的机会减少may not在 2 中的机会。但只有使用可以容纳无限位数的类型才能使may有机会 1.0 和may没有0.0 的机会(当然至少在那种架构下)。因此,无论 modCount 使用多少个有限位,它都不会渐近地产生影响。


查看完整回答
反对 回复 2023-01-05
  • 3 回答
  • 0 关注
  • 105 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信