자바 집합 ArrayList 에서 modCount 상세 설명 및 subList 함수 요점

11468 단어 자바 개발
프로젝트 개발 에서 ArrayList 를 사용 하 는 과정 에서 Concurrent ModificationException 이상 이 발생 했 기 때문에 관련 자 료 를 조회 하여 이 이상 이 발생 한 원인 을 기록 합 니 다.
  이른바 Concurrent ModificationException 을 번역 하면 수정 이상 이 동시에 발생 하 는 것 입 니 다.인터넷 에서 이 이상 이 발생 하 는 원인 은 대부분 교체 기 를 사용 할 때 발생 합 니 다.예 를 들 어:
import java.util.ArrayList;
import java.util.Iterator;

public class Test {

    public static void main(String[] args) {
        ArrayList array = new ArrayList();

        //        
        array.add("hello");
        array.add("world");
        array.add("java");
        Iterator it = array.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            if ("world".equals(s)) {
                array.add("javaee");
            }
        }
    }
}

  이 예 에서 우 리 는 교체 기 를 사용 하여 교체 하 는 과정 에서 집합 을 조작(이곳 의 추가 작업 에 국한 되 지 않 고 삭제 등 일 수도 있 음)하여 교체 기 가 효력 을 잃 고 이 이상 을 던 졌 다.그러나 프로젝트 에서 본인 은 교체 기 를 사용 하지 않 고 다음 코드 가 존재 합 니 다.
List tableEntities = tableData.getValue().subList(1, tableData.getValue().size());
List newEntitys = tableData.getValue().subList(0,1);
List entities = sortTableEntity(tableEntities);
newEntitys.addAll(entities);
tableData.getValue().clear();
tableData.getValue().addAll(newEntitys);

이상 하 게 마지막 단계 에 던 져.이 를 통 해 알 수 있 듯 이 Concurrent ModificationException 이상 은 교체 기 를 사용 할 때 만 나타 나 는 것 이 아니다.Array List 류 의 subList 소스 코드 를 분석 하면 알 수 있 습 니 다.
public List subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

  여기에서 SubList 의 대상 을 되 돌려 주 었 고 그 구조 함수 내부 에서
SubList(AbstractList parent,int offset, int fromIndex, int toIndex) {
    this.parent = parent;
    this.parentOffset = fromIndex;
    this.offset = offset + fromIndex;
    this.size = toIndex - fromIndex;
    this.modCount = ArrayList.this.modCount;
}

  this.modCount=Array List.this.modCount 라 는 코드 를 볼 수 있 습 니 다.첫 번 째 교체 기의 예 에서 iterator()함 수 를 통 해 되 돌아 오 는 교체 기 는 구조 에서 도 사용 되 었 다.
private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

이 이상 한 던 지기 가 modCount 와 관련 이 있 고 modCount 속성 은 AbstractList 추상 류 에서 계승 되 었 음 을 알 수 있 습 니 다.javadoc 문서 의 설명 보기:
The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results. This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods. If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
우 리 는 이 매개 변 수 는 집합 이 수 정 된 횟수 를 기록 하 는 데 사용 되 는 것 을 알 고 있 습 니 다.수 정 된 횟수 를 기록 하려 는 이 유 는 ArrayList 가 스 레 드 가 안전 하지 않 기 때 문 입 니 다.교체 기와 서브 시퀀스 를 사용 하 는 과정 에서 원 집합 에 대한 수정 으로 인해 교체 기와 서브 시퀀스 의 실 효 를 방지 하기 위해 수정 횟수 의 기록 을 저 장 했 습 니 다.교체 기의 조작 과 서브 시퀀스 의 조작 과정 에서먼저 modCount 가 같은 지(함수 check ForComodification())를 확인 하고 기다 리 지 않 으 려 면 집합 이 수정 되 었 다 는 것 을 설명 한다.그러면 후속 적 으로 명확 하지 않 은 오류 가 발생 하지 않도록 이 이상 을 던 졌 다.이 이상 을 방지 하기 위해 서 는 교체 기 를 사용 하여 집합 을 하 는 교체 가 집합 을 수정 하려 면 교체 기 가 제공 하 는 집합 을 조작 하 는 함수 로 이 루어 져 야 한다.그리고 제 코드 에 나타 난 문제 에 대해 다음 과 같이 수정 할 수 있 습 니 다.
List tableEntities = Lists.newArrayList(tableData.getValue().subList(1, tableData.getValue().size()));
List newEntitys = Lists.newArrayList(tableData.getValue().subList(0,1));
List entities = sortTableEntity(tableEntities);
newEntitys.addAll(entities);
tableData.getValue().clear();
tableData.getValue().addAll(newEntitys);

  이렇게 되면 뉴 엔 티 티 스 는 SubList 의 대상 이 아니 라 ArrayList 의 대상 이다.이 상황 도 처음 만 났 고 인터넷 의 다른 해석 은 기본적으로 첫 번 째 상황(즉 교체 기 사용)이 발생 했다.사실 첫 번 째 상황 이 든 두 번 째 상황 이 든 본질은 원래 집합 한 modCount 가 수정 되 어 SubList 의 modCount 나 교체 기의 expected ModCount 와 다 르 기 때문이다.

좋은 웹페이지 즐겨찾기