Item 64. 실패 원자성 달성을 위해 노력하라.

실패 원자성

메소드의 호출이 정상적으로 처리되지 못한 객체의 상태는, 함수 호출 전 상태와 동일해야 한다. 이 속성을 만족하는 함수는 실패 원자성(failure atomicity) 을 갖추었다고 한다.

실패 원자성을 달성하는 방법 몇가지

  1. 불변 객체 : 변경 불가능한 객체의 경우, 함수 호출이 실패하면 새로운 객체가 만들어지지 못할 수는 있지만 기존 객체의 일관성이 깨지지 않는다.
  2. 선행 유효성 검증(pre check validation) : 변경 가능한 객체의 경우, 실제 연산을 수행하기 전에 유효성(validity)을 검사하여 객체를 변경하는 도중에 예외가 발생하는 것을 막아 준다.

        public Object pop(){
            if(size == 0)
                throw new EmptyStackException();
            Object result = elements[--size];
            elements[size] = null; // 만기(obsolete) 참조 제거
            return result;
        }
    

    위 코드 내용 중 if(size == 0) throw new EmptyStackException(); 가 선행 유효성 검증(pre check validation) 부분이다. 이 검증 코드가 없으면, size필드의 일관성이 깨져서 음수로 바뀌게 되어 이 함수를 다시 호출하면 계쇡 문제가 발생한다.

    또는, 객체 상태를 바꾸기 전에, 실패 할 가능성이 있는 코드를 전부 앞쪽에 배치한다.(계산을 실제로 수행해 보기 전에 인자를 검사할 수 없을 때 이용)

  3. rollback : 오류가 발생하면 복구코드가 연산 전 상태로 객체를 되돌린다.
  4. 객체의 임시 복사본(temporary copy) : 객체의 임시 복사본상에서 필요한 연산을 수행하고, 연산이 끝난 다음에 임시 복사본의 내용으로 객체 상태를 바꿈 예를 들어 Collections.sort는 원소드를 참조하는 비용을 줄이기 위해, 인자로 주어진 리스트를 정렬 전에 임시 배열에 복사한다. 그 덕에 저렬이 실패해도 원래 리스트에는 아무런 손상이 없다.

실패 원자성을 달성할 수 없는 경우

명심할 것