자바 fail-fast 와 fail-safe 메커니즘

자바 fail-fast 와 fail-safe 메커니즘
기본 개념
fail-fast 와 fail-safe 라 는 두 개념 은 모두 집합 적 인 병행 수정 과 관련 이 있다.집합 의 병발 수정 이란 한 스 레 드 가 집합 을 옮 겨 다 니 고 있 을 때 다른 스 레 드(또는 스 레 드 자체)가 집합 을 수정 하 는 것 을 말한다.
fail-fast
fail-fast 메커니즘 은 집합 을 옮 겨 다 니 는 과정 에서 집합 이 바 뀐 것 을 발견 하면 Concurrent ModificationException 을 던 지 는 것 을 말한다.보통 다음 과 같은 두 가지 상황 이 있다.
집합 과정 에서 본 수정 집합4.567917.다 중 스 레 드 의 경우 본 스 레 드 는 집합 과정 에서 다른 스 레 드 는 집합 을 수정 했다
fail-fast 검사
ArrayList 코드 의 경우 코드 에서 expected ModCount 가 modCount 로 초기 화 되 었 음 을 알 수 있 습 니 다.그 중에서 modeCount 는 ArrayList 가 수정(add remove)된 횟수 입 니 다.iterator next 와 reove 인 터 페 이 스 는 expected ModCount 와 modCount 가 같 는 지,다 르 면 이상 을 던 집 니 다.
public Iterator iterator() {
    return new Itr();
}

private class Itr implements Iterator {
    protected int limit = ArrayList.this.size;

    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 < limit;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}


하나의 예:
ArrayList list = new ArrayList();
list.add("A");
list.add("B");
list.add("C");
for (String str : list) {
    list.add("D") ;
}

출력 결과:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at TestJava.main(TestJava.java:14)
여기 에는 foreach 순환 에 대한 지식 이 포함 되 어 있 습 니 다.javac 컴 파일 러 는 실제 적 으로 iterator 교체 로 처리 합 니 다.
fail-safe
fail-safe 메커니즘 은 집합 을 옮 겨 다 니 는 과정 에서 집합 이 바 뀌 는 것 을 발견 하면 옮 겨 다 니 는 집합 이 정상적으로 진행 되 는 것 을 말한다.CopyOn Write Array List 를 예 로 들 면:
public Iterator iterator() {
    return new COWIterator(getArray(), 0);
}

static final class COWIterator implements ListIterator {
    /** Snapshot of the array */
    private final Object[] snapshot;
    /** Index of element to be returned by subsequent call to next.  */
    private int cursor;

    COWIterator(Object[] elements, int initialCursor) {
        cursor = initialCursor;
        snapshot = elements;
    }
    //...
}

public boolean add(E e) {
    synchronized (lock) {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    }
}

public E remove(int index) {
    synchronized (lock) {
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elements, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        else {
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        }
        return oldValue;
    }
}

final void setArray(Object[] a) {
    elements = a;
}

코드 에서 볼 수 있 습 니 다:iterator 는 COWIterator 를 되 돌려 줍 니 다.COWIterator 는 실제 적 으로'현재 elements'를 옮 겨 다 니 고 있 습 니 다.매번 오래된 요 소 를 새로운 배열 에 복사 한 다음 에 조작 합 니 다.
하나의 예
CopyOnWriteArrayList list = new CopyOnWriteArrayList();
list.add("A");
list.add("B");
list.add("C");
for (String str : list) {
    System.out.print(str + "\r
"); }

출력 결 과 는:
A B C

좋은 웹페이지 즐겨찾기