Java의 컨테이너 맵과 같은 경우:
for(사람 사람 : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person); //순회 중에는 제거 작업을 수행할 수 없습니다.
}
}
Map을 탐색할 때 일반적으로 해당 키 값의 Set을 얻은 다음 반복자를 사용하여 Map을 탐색합니다.
순회 과정에서는 Map의 요소만 그에 맞게 처리될 수 있으므로 Map 요소를 추가하거나 줄일 수 없습니다. 즉, Map의 크기를 변경할 수 없으며 예외가 발생합니다. 순회 프로세스) 지도의 요소를 수정, 삭제 또는 추가합니다.
보고된 예외는 java.util.ConcurrentModificationException 예외입니다.
공용 클래스 ConcurrentModificationException은 RuntimeException을 확장합니다.
이 예외는 메소드가 객체의 동시 수정을 감지했지만 그러한 수정을 허용하지 않는 경우 발생합니다.
예를 들어 한 스레드가 컬렉션을 반복하는 동안 다른 스레드는 일반적으로 컬렉션을 선형적으로 수정할 수 없습니다. 이러한 경우 반복 결과가 불분명한 경우가 많습니다. 일부 반복기 구현(JRE에서 제공하는 모든 일반 컬렉션 구현 포함)은 이 동작이 감지되면 이 예외를 발생시키도록 선택할 수 있습니다. 이 작업을 수행하는 반복자는 향후 특정 시점에 지정되지 않은 임의 동작의 위험 없이 완전히 빠르게 실패하므로 빠른 실패 반복자라고 합니다.
이 예외는 객체가 다른 스레드에 의해 동시에 수정되었음을 항상 나타내는 것은 아닙니다. 단일 스레드가 개체 계약을 위반하는 일련의 메서드 호출을 실행하는 경우 개체에서 이 예외가 발생할 수 있습니다. 예를 들어 스레드가 빠른 실패 반복기를 사용하여 컬렉션을 반복하는 동안 컬렉션을 직접 수정하는 경우 반복기는 이 예외를 발생시킵니다.
일반적으로 동기화되지 않은 동시 수정이 발생할지 여부를 확실하게 보장할 수 없기 때문에 반복자의 빠른 실패 동작은 보장되지 않습니다. 빠른 실패 작업은 최선을 다해 ConcurrentModificationException을 발생시킵니다. 따라서 이러한 작업의 정확성을 높이기 위해 이 예외에 의존하는 프로그램을 작성하는 것은 실수입니다. 올바른 접근 방식은 다음과 같습니다. ConcurrentModificationException은 버그를 감지하는 데에만 사용해야 합니다.
Collection 또는 Map을 반복하기 위해 빠른 반복기를 사용하는 동안 Collection/Map의 콘텐츠를 직접 수정하려고 하면 단일 스레드에서 실행되는 경우에도 java.util.ConcurrentModificationException 예외가 발생합니다.
Iterator는 별도의 스레드에서 작동하며 뮤텍스 잠금이 있습니다. Iterator가 생성된 후 원본 객체를 가리키는 단일 링크 인덱스 테이블이 설정됩니다. 원본 객체의 수가 변경되면 이 인덱스 테이블의 내용은 동기적으로 변경되지 않으므로 인덱스 포인터가 뒤로 이동할 때 객체를 반복하는 것이 발견되므로 빠른 실패 원칙에 따라 Iterator는 즉시 java.util.ConcurrentModificationException 예외를 발생시킵니다.
따라서 Iterator는 반복되는 객체가 작동하는 동안 변경되는 것을 허용하지 않습니다. 그러나 Iterator의 자체 메소드인 Remove()를 사용하여 객체를 삭제할 수 있습니다. Iterator.remove() 메소드는 인덱스의 일관성을 유지하면서 현재 반복 객체를 삭제합니다.
흥미로운 점은 Collection/Map 객체에 실제로 하나의 요소만 있는 경우 ConcurrentModificationException 예외가 발생하지 않는다는 것입니다. 이것이 javadoc에서 지적된 이유입니다. 정확성을 위해 이 예외에 의존하는 프로그램을 작성하는 것은 잘못된 것입니다. ConcurrentModificationException은 버그를 탐지하는 데에만 사용해야 합니다.