ConcurrentModificationException

4654 단어
원본:http://bbs.csdn.net/topics/370149418
다 들 아 시 겠 지만, 자바 에서 일부 집합 교체 과정 에서 집합 에 대해 수정 작업 을 한다. 예 를 들 어 add, remove 같은 조작 은 잘못 하면 Concurrent Modification Exception 을 버 리 고, 이 점 은 API 문서 에서 도 말 했 습 니 다!   교체 시 교체 기로 만 삭제 할 수 있 습 니 다! 
하지만 문서 에 서 는 삭제 라 고 만 했 을 뿐,  다른 조작 도 Concurrent ModificationException 을 일 으 킬 수 있 습 니 다.  왜 그런 가..? 다음은 나 와 함께 소스 코드 를 탐색 하 자! Array List 를 예 로 들 면!
내 가 Array List 를 교체 할 때, 먼저 Array List 의 교체 기 Array List. iterator () 를 가 져 옵 니 다. 다음은 hasNext 와 next 의 사용 입 니 다. 예 를 들 어:
List list = new ArrayList();
list.add("a");
list.add("b");
for(Iterator it = list.iterator(); it.hasNext;) {
    Object o = it.next();
}

하지만 교체 과정 에서 교체 기로 집합 을 수정 하지 않 았 다 면, 직접 조작 으로 집합 하고,  예 를 들 어 교체 중: list.add(c);
이 럴 때 당신 은 비참 할 수도 있 습 니 다.  왜 절대적 인 것 이 아니 라 가능성 만 있 습 니까?  다음은 이어서 분석 하 겠 습 니 다.
Array List 의 소스 코드 를 따라 보 세 요. iterator () 방법 을 검색 하여 얻 은 교체 기 를 보십시오. 발견 됐어!  그래서 그 부 류 를 쫓 았 다. AbstractList,  iterator () 방법 new 되 돌리 기 Itr()!
Itr 의 두 가지 중요 한 방법 보기:  hasNext 와 next
public boolean hasNext() {
            return cursor != size();
    }
 
    public E next() {
            checkForComodification();
        try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
        } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
        }
    }

next 에서 호출 된 checkForComodification () 을 보십시오. reove 방법 에서 도 checkForComodification () 을 호출 했 습 니 다!이어서 check ForComodification () 방법 에서 무슨 일 을 하고 있 는 지!
final void checkForComodification() {
        if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    }

그래서 교체 과정 에서 hasNext () 는 Concurrent ModificationException 을 던 지지 않 습 니 다. next 와 remove 방법 은 던 질 수 있 습 니 다!  이상 을 던 지 는 기준 이 modCount 입 니 다. != expectedModCount!이 두 변 수 를 계속 추적 합 니 다. Itr 류 의 구성원 변수 에서 expected ModCount 를 초기 화 하 는 할당 값 은 int 입 니 다. expectedModCount = modCount;
그럼 이 modCount 는...? 이것 은 AbstractList 의 proctected 변수 입 니 다.  집합 삭제 작업 에서 모두 modCount 를 수정 하 였 습 니 다.  여 기 는 Array List 를 예 로 들 면, 그래서 Array List 에 부모 클래스 를 덮어 쓰 는 add 가 있 는 지 직접 보 세 요.?   덮 여 있 더 라 고요.
public boolean add(E e) {
    ensureCapacity(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
    }
 
public void ensureCapacity(int minCapacity) {
    modCount++;
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3)/2 + 1;
            if (newCapacity < minCapacity)
        newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

reove 방법 에서 도 modCount + + 를 만 들 었 습 니 다.   내 가 교체 기 를 얻 기 전에, 집합 에 삭제 작업 을 몇 번 이나 추가 하 든, 다 괜찮아, expected ModCount 에 대한 할당 은 교체 기 를 가 져 올 때 초기 화 되 었 기 때 문 입 니 다!
그 러 니까  만약 내 가 집합 추가 삭제 에 대해 모두 10 번 을 조작 했다 면, 이때 modCount 는 10 입 니 다.  교체 기 를 가 져 올 때 expected ModCount 도 10 입 니 다.  교체 기간 에 check ForComodification ()!  next 나 remove 전에 집합 작업 에 대한 동작 이 있 으 면 modCount 가 바 뀌 고, 그 걸 던 지고 이상 을 수정 해 요!
왜 위의 것 이 이상 할 수 있 습 니까? modCount 가 바 뀌 었 을 때, hasNext false 로 돌아 갈 때,  순환 중인 next / remove 방법 을 실행 하지 않 을 것 입 니 다. 이상 하 게 던 지지 않 았 을 거 야!
예 를 들 어 집합 은 현재 하나의 원소 만 있 고,   선 개체 o = it. next (), 그리고 list. remove (o); 이때 modCount 가 바 뀌 었 습 니 다. 하지만 다음 hasNext 는 false 로 돌아 갑 니 다. next 는 실행 되 지 않 기 때문에 이 때 는 이상 을 버 리 지 않 습 니 다!
그래서 여러분 들 은 앞으로 반복 해서 집합 하 는 동시에 집합 작업 에 대해 반드시 조심 하고 조심해 야 합 니 다. 이상 을 던 지지 않 았 다 고 해서 괜찮다 고 생각 하지 마라!
그리고 다 중 스 레 드 가 동시에 발생 할 때 하나의 스 레 드 를 교체 해 야 합 니 다. 집합 작업 을 할 때,  이상 을 던 지지 않 으 면 큰 행운 을 만 날 것 이다!  
google Concurrent ModificationException 을 어떻게 해결 하 는 지 에 대한 방안 은 이미 많 습 니 다. 예 를 들 어 Collections. synchronized Collection () 동기 집합 하 러 가기,  하지만 효율 에 영향 을 미 칠 수 있다.  JDK 5 이후 concurrent 가방 안에 CopyOn Write Array List 가 있 습 니 다. 이 집합 이 교체 되 었 을 때 집합 에 대해 첨삭 작업 을 할 수 있다.  교체 기 에 checkForComodification 이 없 기 때 문 입 니 다!
근 데 왜 그런 지 분석 이 안 되 는 것 같은 데.. 그래서 본문 을 써 서 여러분 께 공유 해 드 렸 습 니 다.   이 글 은 Array List 만 예 로 들 어 왜 Concurrent ModificationException 을 버 렸 는 지, 원리 적 으로 피 하 는 방법 을 설명 했다.집합의 종류 가 매우 많다. 각종 교체 와 집합 작업 의 실현 도 다르다.  예 를 들 어 SubList 의 add 방법 을 보면 checkForComodification 이 있 고 ArrayList 는 없습니다!
그래서 여러분 들 이 나중에 Concurrent ModificationException 을 만나면... 내 가 쓴 이 생각 을 가지 고 하 나 를 들 면 열 을 안다. 마음 을 가 라 앉 히 고 소스 코드 를 찾 으 면 문 제 를 해결 할 수 있 습 니 다!

좋은 웹페이지 즐겨찾기