diff --git "a/10\354\236\245/\354\225\204\354\235\264\355\205\234_76/\352\260\200\353\212\245\355\225\234_\355\225\234_\354\213\244\355\214\250_\354\233\220\354\236\220\354\240\201\354\234\274\353\241\234_\353\247\214\353\223\244\353\235\274.md" "b/10\354\236\245/\354\225\204\354\235\264\355\205\234_76/\352\260\200\353\212\245\355\225\234_\355\225\234_\354\213\244\355\214\250_\354\233\220\354\236\220\354\240\201\354\234\274\353\241\234_\353\247\214\353\223\244\353\235\274.md" new file mode 100644 index 0000000..27fcb17 --- /dev/null +++ "b/10\354\236\245/\354\225\204\354\235\264\355\205\234_76/\352\260\200\353\212\245\355\225\234_\355\225\234_\354\213\244\355\214\250_\354\233\220\354\236\220\354\240\201\354\234\274\353\241\234_\353\247\214\353\223\244\353\235\274.md" @@ -0,0 +1,46 @@ +# 아이템 76: 가능한 한 실패 원자적으로 만들라 + +- 작업 도중 예외가 발생해도 그 객체는 여전히 정상적으로 사용할 수 있는 상태는 참 멋지다. +- 일반화해 이야기하면, 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다. +- 이러한 특성을 실패 원자적이라고 한다. + +## 메서드를 실패 원자적으로 만드는 방법 +- 메서드를 실패 원자적으로 만드는 방법은 다양하다. +- 이어지는 글에서 방법을 하나씩 살펴보자. + +## 실패 원자적으로 만드는 방법 1: 불변 객체 +- 가장 간단한 방법은 불변 객체로 설계하는 것. +- 불변 객체는 태생적으로 실패 원자적이다. +- 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일이 없기 때문 + +## 실패 원자적으로 만드는 방법 2: 코드 배치 수정 +- 실패할 가능성이 있는 모든 코드를 객체의 상태를 바꾸는 코드보다 앞에 배치할 수 있다. +```java +public Object pop() { + if (size == 0) + throw new EmptyStackException(); + Object result = elements[--size]; + element[size] = null; + return result +} +``` +- 위의 코드가 이와 비슷한 취지라고 볼 수 있다. + +## 실패 원자적으로 만드는 방법 3: 객체의 임시 복사본에서 작업을 수행 +- 객체의 복사본에서 작업을 수행하고 작업이 성공적으로 완료되면 원래 객체와 교체하는 방식이다. +- 데이터를 임시 자료구조에 저장해 작업하는 것이 더 빠를 때 쓰기 좋은 방식이다. + +## 실패 원자적으로 만드는 방법 4: 복구 코드를 이용한 롤백 +- 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법이다. +- 자주 쓰이는 방법은 아니다. + +## 실패 원자성을 챙길 수 없는 경우 +- 실패 원자성은 일반적으로 권장되는 덕목. +- 하지만 항상 달성할 수 있는 것은 아니다. +- 예를 들어 두 스레드가 동기화 없이 같은 객체를 동시에 수정한다면 그 객체의 일관성이 깨질 수 있음. +- 따라서 `ConcurrentModificationException`을 잡아냈다고 해서 그 객체가 여전히 쓸 수 있는 상태라고 가정해서는 안된다. +- 그리고 실패 원자적으로 만들 수 있더라도 항상 그리해야 하는 것도 아니다. +- 실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산도 있기 때문. +- 메서드 명세에 기술한 예외라면 설혹 예외가 발생하더라도 객체의 상태는 호출 전과 똑같이 유지돼야 한다는 것이 기본 규칙이다. +- 이 규칙을 지키지 못한다면 실패 시의 객체 상태를 API설명에 명시해야 한다. +- 이것이 이상적이지만 아쉽게도 지금의 API문서 상당 부분이 잘 지키지 않고 있다.