简体   繁体   English

为什么API在ArrayList的子列表的列表迭代器的next()中引发并发修改异常?

[英]Why the API throws Concurrent Modification Exception in next() of list iterator of the sub list in ArrayList?

This is in reference to the first level sub list of an arraylist. 这是参考arraylist的第一级子列表。

We have this source code- 我们有此源代码-

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;   // initially cursor is set to 0
            if (i >= SubList.this.size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (offset + i >= elementData.length)
                throw new ConcurrentModificationException();  // WHY? 
            cursor = i + 1;
            return (E) elementData[offset + (lastRet = i)];
        }

Why throw a ConcurrentModificationException instead of IndexOutOfBoundsException ? 为什么抛出ConcurrentModificationException而不是IndexOutOfBoundsException

Why concurrent? 为什么要并发?


NOTE:- 注意:-

I am still struggling with the design part. 我仍在努力设计部分。

This is in reference to the comment by @Kayaman 这是参考@Kayaman的评论

Consider the below arraylist and its sublist- 考虑下面的arraylist及其子列表-

el      original    sublist
0       a[0]
10      a[1]
20      a[2]        s[0]
30      a[3]        s[1]
40      a[4]        s[2]
50      a[5]        s[3]
60      a[6]        s[4]
70      a[7]
80      a[8]
90      a[9]

Every sublist has 2 instance variables 每个子列表都有2个实例变量

parent offset - diff b/w the first index location of parent and sub list. 父级偏移量-diff黑白父级和子级列表的第一个索引位置。

offset - diff b/w the first index location of original and sub list. offset-diff b / w 原始列表和子列表的第一个索引位置。

There is internally an array elementData which backs this arraylist Even if some thread removes an element from the original arraylist (concurrent modification), the size gets reduced by 1 , but the length of elementData remains the same. 内部有一个支持此arraylist的数组elementData即使某些线程从原始arraylist中removes了一个元素(并发修改),其大小也减小了1 ,但是elementData的length保持不变。

fast remove internally c/d by remove(Object) - 通过remove(Object)内部fast remove c / d-

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

I see that this condition will never be fulfilled- offset + i >= elementData.length even after removal concurrently. 我看到永远不会满足此条件-即使同时删除后, offset + i >= elementData.length

Any suggestions? 有什么建议么?

Because on creation of the Sublist , a range check is performed: 因为在创建Sublist ,将执行范围检查:

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, offset, fromIndex, toIndex);
}

So the Sublist will never go beyond the end of the source list. 因此, Sublist列表永远不会超出源列表的末尾。

Therefore, offset + i will always be inside the valid range of the original List except it has been modified in the meantime. 因此, offset + i始终在原始List的有效范围内, 除非同时已对其进行了修改。

Note that Sublist takes any AbstractList<> as its source List ; 注意Sublist将任何AbstractList<>作为其源List so even if ArrayList itself does not shrink its backing array on a remove, a subclass might do so - which would cause Sublist to be incorrect here. 因此,即使ArrayList本身在删除时不收缩其后备数组,子类也可能这样做-这将导致Sublist在此处不正确。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM