簡體   English   中英

為什么這個 Java 代碼會觸發 ConcurrentModificationException?

[英]Why does this Java code trigger a ConcurrentModificationException?

在循環的第一行我得到了錯誤,但我不明白為什么。 從我讀到的內容來看,只有當我迭代一個集合並嘗試同時修改它時才會發生這種情況,但事實並非如此。

在代碼中, list的類型是ArrayList<Product>

void mergeSort() { 
    mergeSort(0, list.size() - 1); //128
}

private void mergeSort(int p, int r) {
    if (p < r) {
        int q = (p + r) / 2;
        mergeSort(p, q); //133
        mergeSort(q + 1, r);
        merge(p, q, r); //135
    }
}

private void merge(int p, int q, int r) {
    List<Product> left = list.subList(p, q);
    left.add(Product.PLUS_INFINITE);
    List<Product> right = list.subList(q + 1, r);
    right.add(Product.PLUS_INFINITE);
    int i = 0;
    int j = 0;
    for (int k = p; k <= r; ++p) {
        Product x = left.get(i).compareTo(right.get(j)) <= 0 ? left.get(i++) : right.get(j++); //147
        list.set(k, x);
    }
}

這是堆棧跟蹤:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1415)
    at java.base/java.util.ArrayList$SubList.get(ArrayList.java:1150)
    at ProductList$ProductSort.merge(MainClass.java:147)
    at ProductList$ProductSort.mergeSort(MainClass.java:135)
    at ProductList$ProductSort.mergeSort(MainClass.java:133)
    at ProductList$ProductSort.mergeSort(MainClass.java:128)
    at ProductList.sort(MainClass.java:95)
    at MainClass.main(MainClass.java:187)

subList不會創建與指定范圍內的原始列表具有相同元素的新列表。 相反,它創建了一個“視圖”( docs ):

返回此列表部分的視圖 [...]。 返回的列表由該列表支持,因此返回列表中的非結構性更改會反映在該列表中,反之亦然。

另請注意:

如果后備列表(即此列表)以除通過返回列表之外的任何方式進行結構修改,則此方法返回的列表的語義將變為未定義。

這正是您在merge中所做的。 您正在創建子列表left 然后用add在結構上修改left 到目前為止,一切都很好。 但是隨后您創建了另一個子列表並對其進行right修改。 這使得“ left的語義變得未定義”。 這會導致下一次調用get拋出異常。

最小的可重現示例:

ArrayList<String> list = new ArrayList<>(List.of("1", "2", "3", "4"));
List<String> left = list.subList(0, 2);
List<String> right = list.subList(2, 4);
right.add("5");
left.get(0);

子列表在這方面有點像迭代器( 您只能通過迭代器remove ,如果您通過原始列表刪除,可能會拋出 CME )。

解決此問題的一種簡單方法是創建子列表的副本,以便它們不再是“視圖”,而是實際上是獨立的列表:

List<Product> left = new ArrayList<>(list.subList(p,q));
List<Product> right = new ArrayList<>(list.subList(q+1,r));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM