简体   繁体   English

Java同级移除会引发ConcurrentModificationException

[英]Java sibling removal throws ConcurrentModificationException

I'm having the following issue: 我遇到以下问题:

Given: 鉴于:

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

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

All the elements of linkedElements belongs to elements too. linkedElements的所有元素也属于元素。 I want that each time that an element is deleted from the elements collection, its linked elements gets deleted from that collection too. 我希望每次从元素集合中删除一个元素时,其链接的元素也会从该集合中删除。 I've tried attaching a observer to the Iterator.remove operation and fire there the removal of linkedElements from the elements list, but because of the logic itself, I always run into a ConcurrentModificationException. 我尝试将观察者附加到Iterator.remove操作上,并在该位置触发从元素列表中删除linkedElements,但是由于逻辑本身,我总是遇到ConcurrentModificationException。

Update: This is the code that causes the error: 更新:这是导致错误的代码:

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);
        }
    }

  }
}

With this code, just calling a A.getElements().clear() will fire a ConcurrentModificationException ... and its ok, because I'm removing all linked elements from from the elements list while removing one single element. 使用此代码,仅调用A.getElements().clear()将触发ConcurrentModificationException ...及其确定,因为我要从元素列表中删除所有链接的元素,同时删除一个元素。 That's why I need another approach. 这就是为什么我需要另一种方法。

It's because you're modifying the array while you're iterating over it. 这是因为您在迭代数组时正在修改数组。 From the javadocs for ArrayList: 从ArrayList的javadocs中:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. 此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时间以任何方式对列表进行结构修改,除非通过迭代器自己的remove或add方法,否则迭代器将抛出ConcurrentModificationException。 Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. 因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险。

So, once you do A.this.getElements().remove(linkedElement); 因此,一旦执行A.this.getElements().remove(linkedElement); in the remove method, you've now just structurally modified the list via a means other than the iterator it 's "remove" method, which means the iterator will throw the CME. 在remove方法,你现在只是通过结构比其他迭代的手段修改列表it的‘删除’的方法,这意味着迭代器都将抛出CME。

Dealing with this will probably be tricky. 处理这个可能很棘手。 I can think of a few options offhand, all of which have complications: 我可以想到一些备选方案,所有这些方案都有复杂性:

  • Switch to CopyOnWriteArrayList , since its iterators are fail-safe. 切换到CopyOnWriteArrayList ,因为其迭代器是故障安全的。 Downside is that your iterator may potentially still show items that were removed previously. 缺点是您的迭代器可能仍会显示以前删除的项目。 (On the other hand, you have to deal with that sort of risk anyway, since you could also have already iterated past a child of whatever you're removing.) If this works for you, this is almost certainly the easiest and most reliable option. (另一方面,无论如何,您都必须应对这种风险,因为您可能已经遍历了要删除的所有内容的子项。)如果这对您有用,那么几乎可以肯定这是最简单,最可靠的方法选项。
  • Following the for loop in remove , replace it with a new Iterator that you manually advance to the correct location. remove的for循环之后,将it替换为新的Iterator,您可以手动将其迭代到正确的位置。 Hard to do if your list allows duplicate items. 如果您的列表允许重复项,则很难做到。
  • Re-implement ArrayList.Iterator; 重新实现ArrayList.Iterator; in your remove method, you can track the changes you're making and update your iterator appropriately. remove方法中,您可以跟踪所做的更改并适当地更新迭代器。

Finally, as a last question / warning - do you want this traversal to be recursive? 最后,作为最后一个问题/警告-您是否希望这种遍历是递归的? Right now, if you had elements Foo linked to Bar, and Bar linked to Baz, removing Foo from the iterator would result in Bar being removed, but there's nothing that would then remove Baz. 现在,如果您将元素Foo链接到Bar,并将Bar链接到Baz,则从迭代器中删除Foo将导致删除Bar,但是没有什么可以删除Baz。 (Whereas if you removed Bar first, then Baz would be removed.) In general if you want to modify the removal behavior of a Collection , you'd be better off doing it List.remove rather than Iterator.remove . (但是,如果先删除Bar,则将Baz删除。)通常,如果要修改Collection的删除行为,最好将其设置为List.remove而不是Iterator.remove

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 抛出java.util.ConcurrentModificationException - Throws java.util.ConcurrentModificationException Java forEach lambda引发并发ModificationException - Java forEach lambda throws concurrentModificationException HashMap迭代/删除获取java.util.ConcurrentModificationException - HashMap iteration/removal getting java.util.ConcurrentModificationException JFreeChart抛出java.util.ConcurrentModificationException - JFreeChart throws java.util.ConcurrentModificationException Java 迭代集合在保存后抛出 ConcurrentModificationException - Java iterating collection throws ConcurrentModificationException after Save ListIterator 抛出“线程“main”中的异常 java.util.ConcurrentModificationException”Java - ListIterator throws "Exception in thread "main" java.util.ConcurrentModificationException" Java Java在我的代码上抛出java.util.ConcurrentModificationException - java throws java.util.ConcurrentModificationException on my code Spark 流在添加 JsonArray 时抛出 java.util.ConcurrentModificationException - Spark streaming throws java.util.ConcurrentModificationException while adding JsonArray 对已排序的列表进行排序时,列表迭代会在Java 8中引发ConcurrentModificationException - List iteration throws ConcurrentModificationException in Java 8 when sorting already sorted list Java-ConcurrentModificationException - Java - ConcurrentModificationException
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM