在下面的代碼片段中,為 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()?,F在,看看這個: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 回答

ITMISS
TA貢獻1871條經驗 獲得超8個贊
您所做的一切都是創建一個場景,在該場景中,modCount 最終會環繞,直到它處于某種狀態以反映沒有發生修改,因此沒有 CME。也許您希望 modCount 是 long 而不是 int。

瀟湘沐
TA貢獻1816條經驗 獲得超6個贊
稍加思索后,我得出結論:
如果 Iterator 拋出 a
ConcurrentModificationException
,則源在正在進行的迭代中進行了結構修改。如果源在其迭代器處于正在進行的迭代中時在結構上被修改,則該迭代器可能會或可能不會拋出
ConcurrentModificationException
.
考慮到這一點,迭代器嘗試拋出 a 的唯一原因ConcurrentModificationException
是幫助調試。總比沒有好,尤其是在一般情況下。
在 modCount 中使用 long 而不是 int 將增加 may 的機會并減少may not在 2 中的機會。但只有使用可以容納無限位數的類型才能使may有機會 1.0 和may沒有0.0 的機會(當然至少在那種架構下)。因此,無論 modCount 使用多少個有限位,它都不會漸近地產生影響。
添加回答
舉報
0/150
提交
取消