簡體   English   中英

Java同級移除會引發ConcurrentModificationException

[英]Java sibling removal throws ConcurrentModificationException

我遇到以下問題:

鑒於:

public class A{
    Collection<B> elements = new ArrayList<B>();
}

public class B{
    Collection<B> linkedElements = new ArrayList<B>();
}

linkedElements的所有元素也屬於元素。 我希望每次從元素集合中刪除一個元素時,其鏈接的元素也會從該集合中刪除。 我嘗試將觀察者附加到Iterator.remove操作上,並在該位置觸發從元素列表中刪除linkedElements,但是由於邏輯本身,我總是遇到ConcurrentModificationException。

更新:這是導致錯誤的代碼:

public class A{
 Collection<B> elements = new ArrayList<B>(){
    public Iterator<B> iterator() {
        return new ProxyIterator(super.iterator());
    };

  private class ProxyIterator implements Iterator{

    Iterator it;

    Object lastObject;

    public ProxyIterator(Iterator proxied){
        it = proxied;
    }

    @Override
    public boolean hasNext() {
        return it.hasNext();
    }

    @Override
    public Object next() {
        return lastObject = it.next();
    }

    @Override
    public void remove() {
        it.remove()
        for (B linkedElement : ((B)lastObject).getlinkedElements()) {
            A.this.getElements().remove(linkedElement);
        }
    }

  }
}

使用此代碼,僅調用A.getElements().clear()將觸發ConcurrentModificationException ...及其確定,因為我要從元素列表中刪除所有鏈接的元素,同時刪除一個元素。 這就是為什么我需要另一種方法。

這是因為您在迭代數組時正在修改數組。 從ArrayList的javadocs中:

此類的迭代器和listIterator方法返回的迭代器是快速失敗的:如果在創建迭代器之后的任何時間以任何方式對列表進行結構修改,除非通過迭代器自己的remove或add方法,否則迭代器將拋出ConcurrentModificationException。 因此,面對並發修改,迭代器會快速干凈地失敗,而不會在未來的不確定時間內冒任意,不確定的行為的風險。

因此,一旦執行A.this.getElements().remove(linkedElement); 在remove方法,你現在只是通過結構比其他迭代的手段修改列表it的‘刪除’的方法,這意味着迭代器都將拋出CME。

處理這個可能很棘手。 我可以想到一些備選方案,所有這些方案都有復雜性:

  • 切換到CopyOnWriteArrayList ,因為其迭代器是故障安全的。 缺點是您的迭代器可能仍會顯示以前刪除的項目。 (另一方面,無論如何,您都必須應對這種風險,因為您可能已經遍歷了要刪除的所有內容的子項。)如果這對您有用,那么幾乎可以肯定這是最簡單,最可靠的方法選項。
  • remove的for循環之后,將it替換為新的Iterator,您可以手動將其迭代到正確的位置。 如果您的列表允許重復項,則很難做到。
  • 重新實現ArrayList.Iterator; remove方法中,您可以跟蹤所做的更改並適當地更新迭代器。

最后,作為最后一個問題/警告-您是否希望這種遍歷是遞歸的? 現在,如果您將元素Foo鏈接到Bar,並將Bar鏈接到Baz,則從迭代器中刪除Foo將導致刪除Bar,但是沒有什么可以刪除Baz。 (但是,如果先刪除Bar,則將Baz刪除。)通常,如果要修改Collection的刪除行為,最好將其設置為List.remove而不是Iterator.remove

暫無
暫無

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

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