CopyOnWriteArrayList 抛出 CurrentModificationException

当我迭代列表时,我偶尔会得到一个。谷歌搜索告诉我,这可能是因为我在另一个线程中更改了该列表,同时对其进行了迭代,为了使这个问题消失,我应该使用....ConcurrentModificationExceptionjava.util.concurrent.CopyOnWriteArrayList

...除了我已经是。

显然,我在某个地方做了一些非常愚蠢的事情。

有没有人对如何诱使投掷有任何见解?如果这很重要,我正在使用Java 5。CopyOnWriteArrayListConcurrentModificationException

编辑:由于我使用的突变体可能很重要,因此我以两种方式修改此列表:

  • 在前面添加元素。(list.add(0, newElement);)
  • 使用 subList 让较旧的项目从后面掉下来。(list = list.subList(0, MAX_LIST_SIZE);)

这些会引发危险信号吗?如果是,为什么?我的理解是,因为这些操作首先复制了事物,因此任何现有的迭代器都将指向未修改的原始值,因此不会在意。我的知识有漏洞吗?

编辑 2:导致问题的精确代码仍然有点模糊,但我至少可以发布我看到的异常:


java.util.ConcurrentModificationException
    at java.util.concurrent.CopyOnWriteArrayList$COWSubList.checkForComodification(Unknown Source)
    at java.util.concurrent.CopyOnWriteArrayList$COWSubList.iterator(Unknown Source)
    at....

...其中,它指向我的代码中的 for-each 循环实例化。

这似乎确实意味着,我的呼吁是我问题的根源。我的问题根源。我仍然想知道为什么。COWSubListsubList

编辑3:*面部手掌*

CopyOnWriteArrayList.subList()返回 一个 ,而不是一个 。它返回的清单没有提供任何COWAL保护的默示义务。这使得使用这样的方法来删除元素是一个非常糟糕的主意。ListCopyOnWriteArrayListsubList()

不确定这是否是我的罪魁祸首,但它是该死的可疑,无论如何都需要纠正。


答案 1

CopyOnWriteArrayList.subLists 如果包含列表从其下方更改出来,则会抛出 ConcurrentModificationExceptions:

public class ListTest {

  private static List<int[]> intList;

  public static void main (String[] args) {
    CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
    cowal.add(1);
    cowal.add(2);
    cowal.add(3);

    List<Integer> sub = cowal.subList(1, 2);
    cowal.add(4);
    sub.get(0); //throws ConcurrentModificationException
  }
}

答案 2

Sbodd有正确的答案,但听起来使用CopyOnWriteArrayList而不是ArrayList只是试图掩盖错误。真正的问题是在迭代基础列表时尝试修改它。您需要找到代码中访问它的位置,并删除该用法或绕过它。