【问题标题】:What leads to ConcurrentModificationException是什么导致 ConcurrentModificationException
【发布时间】:2018-05-18 17:49:49
【问题描述】:

我正在阅读有关 ConcurrentModificationException 的信息。我为迭代器找到了这段代码。谁能解释导致这个异常的真正原因。我只想为下面写的逻辑提供一些理由。

public boolean hasNext() {
    return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

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

【问题讨论】:

  • 您有什么具体问题吗? “那里有一些我不理解的代码”不是问题,这是事实,因为任何人一生都可以理解更多的代码。至少乍一看,这段特定的代码看起来不错。
  • 当然,代码看起来不错。但我无法理解这些行: Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException();

标签: java collections concurrency iterator concurrentmodification


【解决方案1】:

当您迭代它们时,您的底层元素数量正在改变大小,因此会引发异常。

请注意,这里的尝试不是从不可能的情况中恢复,而是尽可能早且干净地“失败”。不抛出异常并使某些东西起作用可能很容易,但是行为是未定义的。这是尽一切可能确保您的迭代器中没有编码错误,而不仅仅是从不可能的代码角落中恢复。

// This line is getting the underlying array out from "this" ArrayList   
Object[] elementData = ArrayList.this.elementData; 

// I is the current value of your cursor.  Every time you call "next"
// this cursor is being incremented to get the next value
// This statement is asking if your current cursor extends beyond the
// end of the array, if it does then "Something" happened to make the array
// smaller while we weren't looking...
if (i >= elementData.length) 
    // To indicate that the elementData array has changed size outside of
    // our current iterator, throw an exception to the user.
    throw new ConcurrentModificationException();

因此,要使这种情况发生,您将创建一个迭代器,然后减小数组列表的大小,然后调用“Next”。这应该会给你一个 CME

【讨论】:

  • 你能在这里解释一下这一行吗,我不明白这个 elementData 到底在做什么: Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException();
  • 如果elementData 的长度由于外部列表中的删除而发生变化,i 可能已经elementData 中的一个有效索引,但现在不在边界,elementData[i]现在会抛出一个IndexOutOfBoundsException。该代码块引发了一个异常,该异常解决了问题的实际原因,即ArrayList 与迭代同时修改,而不是@987654328 的症状 @ 现在越界了。
  • @Bill K 感谢您的解释!但正如你所说,我有一个疑问,我必须删除一个元素并调用“下一步”才能获得上述异常。在删除元素(即“删除”方法)期间不应该处理。如果是,在“下一步”期间再次检查有什么意义。
  • 当您使用 ArrayList.remove() 删除元素时,实现实际上并不“知道”您正在对其进行迭代——只有迭代器知道这一点。所以迭代器是必须“注意到”它并抛出异常的那个。有一个 iterator.remove() 方法实际上确实知道并在删除元素后为您调整所有内容,以便它不会引发异常。
猜你喜欢
  • 2021-10-20
  • 2015-09-15
  • 2013-01-18
  • 1970-01-01
  • 2010-12-31
  • 2013-03-10
  • 2011-03-12
相关资源
最近更新 更多