HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📖
공부한 책
/
📒
Effective Java
/
아이템 76: 가능한 한 실패 원자적으로 만들라

아이템 76: 가능한 한 실패 원자적으로 만들라

💡
일반화해 이야기하면, 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 함 ↔ Failure-atomic 메서드 명세에 기술한 예외라면 설혹 예외가 발생하더라도 객체의 상태는 메서드 호출 전과 똑같이 유지돼야 한다는 것이 기본규칙이다. 이 규칙을 지키지 못한다면 실패 시의 객체 상태를 API 설명에 명시해야 한다

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

  1. 불변 객체로 만드는 방법. 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 결코 없음
  1. 유효성 검사, 실패 가능성 있는 코드 앞에 배치
    1. 가변 객체의 메서드를 실패 원자적으로 만드는 가장 흔한 방법은 작업 수행에 앞서 매개변수의 유효성을 검사하는 것
      public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; return result; }
      • if 부분을 빼게 되면, size가 음수가 되어버릴 수 있으니 실패 원자적이 될 수 없다
      비슷한 취지로, 실패할 가능성이 있는 모든 코드를, 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법 (계산 수행해보기 전에는 인수의 유효성을 검사해 볼 수 없을 때 위의 방식에 덧붙여 쓸 수 있는 기법)
      • TreeMap을 예시로 생각해보면, 해당 인스턴스에 원소 추가하려면 그 원소는 TreeMap의 기준에 따라 비교할 수 있는 타입이어야 하고, 그렇지 않다면 ClassCastException을 던지게 됨
  1. 객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체하는 것
  1. 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법

실패 원자성 달성 못하는 경우, 필요없는 경우

실패 원자성은 일반적으로 권장되는 덕목이지만 항상 달성할 수 있는 것은 아니다. (예: 동시성 문제, Error)
  • 예를 들어 두 스레드가 동기화 없이 같은 객체를 동시에 수정한다면 그 객체의 일관성이 깨질 수 있음
  • ConcurrentModificationException을 잡아냈다고 해서 그 객체가 여전히 쓸 수 있는 상태라고 가정해서는 안됨
  • Error는 복구할 수 없으므로 AssertionError에 대해 실패 원자적으로 만들려는 시도조차 할 필요 없음
  • 실패 원자적으로 만들 수 있더라도 항상 그리 해야 하는 것도 아니다 (실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산)