스터디/이펙티브 자바

[Effective Java] Item 76. 가능한 한 실패 원자적으로 만들라

📝 작성 : 2022.09.18  ⏱ 수정 : 

실패 원자적

호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다는 내용입니다.

실패 원자적으로 만드는 방법

불변 객체로 설계

불변 객체는 태생적으로 실패 원자적입니다. 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일이 없습니다. 불변 객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문입니다.

작업 수행에 앞서 매개변수의 유효성 검사

public Object pop() {
    if(size == 0){
        throw new EmptyStackException();
    }
    Object result = elements[--size];
    elements[size] = null; // 다쓴 참조 해제
    return result;
}

if 문이 없더라도 스택이 비어있다면 예외를 던지지만 size의 값이 음수가 되어 다음 호출도 실패하며, 이때 던지는 ArrayIndexOutOfBoundException은 추상화 수준이 상황에 어울리지 않습니다.

객체의 임시 본사본을 사용

객체의 임사 복사본에서 작업을 수행한 다음, 작업이 성공하면 원래의 객체와 교체하는 방법입니다. 데이터의 임시 자료구조에 작업하는게 빠를 때 적용하기 좋은 방식입니다.

예를 들어, 정렬 메서드에서 정렬을 수행하기 전에 입력 리스트의 원소들을 배열로 옮겨 담습니다. 배열을 사용하면 정렬 알고리즘의 반복문에서 원소들에 훨씬 빠르게 접근할 수 있기 때문입니다. 혹시나 정렬에 실패하더라도 입력 리스트는 변하지 않는 효과를 얻을 수도 있습니다.

실패를 가로채서 복구

디스크 기반의 내구성(durability)를 보장해야 하는 자료구조에서 사용하는 방법입니다. 자주 사용되지는 않습니다.

실패 원자성의 현실

실패 원자성은 권장되지만 항상 달성할 수 있는 것은 아닙니다.

예를 들어, 두 쓰레드가 동기화 없이 같은 객체에 접근, 수정한다면 객체의 일관성이 깨질 수 있습니다. 따라서 ConcurrentModificationException 잡아냈더라도 그 객체가 여전히 사용할 수 있는 상태라고 가정해서는 안됩니다.

또, 실패 원자성을 달성하기 위한 비용, 복잡도가 아주 큰 연산이 있는 경우에도 실패 원자적으로 만들었을 때의 득과 실을 잘 따져보아야 합니다.

반응형