source

java.util이 왜 안 뜨죠?동시 수정이 예에서는 예외입니까?

gigabyte 2022. 9. 1. 23:20
반응형

java.util이 왜 안 뜨죠?동시 수정이 예에서는 예외입니까?

주의: 다음 사항을 알고 있습니다.Iterator#remove()★★★★★★ 。

다음 코드 샘플에서, 저는 왜 이 코드 샘플이List.removemain가 「」를 슬로우 합니다.ConcurrentModificationException, 에는 없습니다.remove★★★★★★ 。

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer toRemove) {
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer toRemove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }
}

그 이유는 다음과 같습니다.Javadoc에 기재되어 있습니다.

이 클래스의 반복자 및 listIterator 메서드에 의해 반환되는 반복자는 fail-fast입니다.반복자 자신의 삭제 또는 추가 메서드를 제외한 어떤 방법으로든 목록이 구조적으로 변경되면 반복자는 Concurrent Modification을 슬로우합니다.예외.

는 이이 the the the the the the the the the 에서 합니다.next()(스택 트레이스에서 알 수 있듯이) 반복기의 메서드입니다.는 그 곳에 입니다.next()는 「」의 경우에 됩니다.hasNext() 에 입니다.에서는, 「」가 때,hasNext()는 다른 요소를 반환할 필요가 있는지 여부를 체크하고 2개의 요소를 반환한 것을 확인합니다.한 요소가 삭제되면 목록에는 2개의 요소만 포함됩니다.그래서 모든 것이 복숭아색이고 우리는 반복하는 것을 끝냈다.대한 . 변경에 대한 검사는 되지 않습니다.next()이치노

다음은 두 번째 루프입니다.두 번째 번호를 삭제하면 hasNext 메서드는 더 많은 값을 반환할 수 있는지 다시 확인합니다.이미 2개의 값을 반환했지만 목록에는 1개만 포함되어 있습니다.하지만 여기서의 암호는

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

되므로 1!= 2로 .next()method: 누군가가 목록을 조작하고 있음을 인식하고 예외를 발생시킵니다.

이것으로 의문이 풀리길 바랍니다.

요약

List.remove() 않다ConcurrentModificationException목록에서 두 번째 마지막 요소를 제거합니다.

한 가지 은, 입니다.Collection( ) 、 ( ) 、 ( ) ) ( ) ) 。 Clone은 복하 a a a a a a를 통해 하기 위한 이다.Constructor.

이 예외는 객체의 동시 변경을 검출한 메서드에 의해 발생할 수 있습니다.이러한 변경은 허용되지 않습니다.

인 경우,는 신의, 선,, 선엔이 final했을 때 사용하는 방법입니다.

private static final List<Integer> integerList;

또한 원래 목록 대신 복사본을 수정하십시오.

List<Integer> copy = new ArrayList<Integer>(integerList);

for(Integer integer : integerList) {
    if(integer.equals(remove)) {                
        copy.remove(integer);
    }
}

항목을 제거할 때 정방향/반복기가 작동하지 않습니다.오류 없이 요소를 제거할 수 있지만 제거된 항목에 액세스하려고 하면 런타임 오류가 발생합니다.반복기를 사용할 수 없습니다. 반복기를 누르면 Concurrent Modification이 발생합니다.예외는 일반 for 루프를 대신 사용합니다.단, 루프는 뒤로 물러나 주세요.

List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);

int size= integerList.size();

//Item to remove
Integer remove = Integer.valueOf(3);

해결책:

목록 요소를 제거하려면 배열을 역순으로 이동합니다.목록을 뒤로 이동하기만 하면 제거된 항목이 나타나지 않으므로 예외가 제거됩니다.

//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
    if (integerList.get(i).equals(remove) ) {
        integerList.remove(i);
    }
}

이 스니펫은 항상 Concurrent Modification을 슬로우합니다.예외.

규칙은 "반복기(각 루프를 사용할 때)를 사용하여 반복하는 동안 목록에서 요소를 수정(추가 또는 제거)할 수 없습니다."입니다.

Java Docs:

이 클래스의 반복자 및 listIterator 메서드에 의해 반환되는 반복자는 fail-fast입니다.반복자 자신의 삭제 또는 추가 메서드를 제외한 어떤 방법으로든 목록이 구조적으로 변경되면 반복자는 Concurrent Modification을 슬로우합니다.예외.

따라서 목록(또는 일반적인 컬렉션)을 수정하는 경우 반복기를 사용하십시오.그러면 변경 내용이 인식되기 때문에 올바르게 처리되기 때문입니다.

이게 도움이 됐으면 좋겠다.

나도 같은 문제가 있었지만 반복 목록에 en 요소를 추가할 경우를 대비해서.내가 이렇게 만들었어

public static void remove(Integer remove) {
    for(int i=0; i<integerList.size(); i++) {
        //here is maybe fine to deal with integerList.get(i)==null
        if(integerList.get(i).equals(remove)) {                
            integerList.remove(i);
        }
    }
}

목록 위에 반복기를 만들지 않고 "수동적으로" 반복하기 때문에 모든 것이 잘 진행됩니다. 조건 리건 and and andi < integerList.size()List decrement / increment list size에사이즈입니다.

그게 도움이 됐으면 좋겠는데, 그게 해결책이었어.

copy-on-write 컬렉션을 사용하면 동작합니다.단, list.iterator()를 사용하면 반환된Iterator는 (아래와 같이) list.iterator()가 호출되었을 때와 같은 요소의 컬렉션을 항상 참조합니다.다른 스레드가 컬렉션을 변경해도 마찬가지입니다.Copy-on-Write 기반 Iterator 또는 ListIterator(추가, 설정, 삭제 등)에서 호출된 변환 메서드는 Unsupported Operation을 슬로우합니다.예외.

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new CopyOnWriteArrayList<>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer remove) {
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer remove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }
}

Java 1.6에서는 정상적으로 동작합니다.

~ % javac RemoveListElementDemo.java
최대 % Java RemoveListElementDemo
~ % cat RemoveListElementDemo.java

import java.util.*;
public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer remove) {
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer remove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(remove)) {                
                integerList.remove(integer);
            }
        }
    }
}

~ %

저 같은 경우에는 이렇게 했어요.

int cursor = 0;
do {
    if (integer.equals(remove))
        integerList.remove(cursor);
    else cursor++;
} while (cursor != integerList.size());

변경 반복기for each안으로for loop해결할 수 있습니다.

그 이유는 다음과 같습니다.

이 클래스의 반복자 및 listIterator 메서드에 의해 반환되는 반복자는 fail-fast입니다.반복자 자신의 삭제 또는 추가 메서드를 제외한 어떤 방법으로든 목록이 구조적으로 변경되면 반복자는 Concurrent Modification을 슬로우합니다.예외.

-- 참조된 Java Docs.

코드맨을 확인해...

주요 방법에서는 존재하지 않는 네 번째 요소를 제거하려고 하므로 오류가 발생합니다.remove() 메서드에서는 세 번째 요소를 삭제하려고 하므로 오류가 없습니다.

언급URL : https://stackoverflow.com/questions/8189466/why-am-i-not-getting-a-java-util-concurrentmodificationexception-in-this-example

반응형