From 6cae5e15415f82a329f9a1c338c8d10aef226618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A6=AC=EB=B9=84?= <Leekh10195@gmail.com> Date: Tue, 11 Jun 2024 11:01:37 +0900 Subject: [PATCH] =?UTF-8?q?post(=EC=95=84=EC=9D=B4=ED=85=9C=2076):=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=ED=95=9C=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=EC=9B=90=EC=9E=90=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A4=EB=9D=BC.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4_\353\247\214\353\223\244\353\235\274.md" | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 "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" 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문서 상당 부분이 잘 지키지 않고 있다.