아이템5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
ksy90101 opened this issue · comments
왜 의존객체가 불변이 되면 여러 클라이언트가 의존 객체들을 공유할 수 있는지 모르겠어요 ㅠ
우선 제 생각을 말씀드리기 전에, 제가 발표 자료에서 아래와 같이 준비했는데 오해의 소지가 있어서 정정할게요!! ㅠㅠ
의존 객체 주입 패턴의 장점
- 자원이 몇개든 의존관계가 어떻든 상관없이 잘 동작한다
- 불변이므로 여러 클라이언트가 의존 객체들을 공유할 수 있다
- 유연하고 테스트가 쉽다
위에서 "여러 클라이언트가 의존 객체들을 공유할 수 있다"를 의존 객체 주입 패턴의 장점인 것처럼 썼는데 위 장점은 불변객체의 장점입니다. 그래서 아래처럼 바꿨어요
의존 객체 주입 패턴의 장점
- 자원이 몇개든 의존관계가 어떻든 상관없이 잘 동작한다
- 유연하고 테스트가 쉽다
또한, 의존 객체가 불변이라면, 여러 클라이언트가 의존 객체들을 공유할 수 있다
아래 링크가 불변객체와 thread-safe에 대한 좋은 예시를 보여주고 있는 것 같아요.
https://devonce.tistory.com/26
위 링크에서 StringBuilder은 가변이므로 여러 쓰레드에서 접근했을 때 문제가 발생했습니다
-> 의존 객체를 공유할 수 없었습니다 (정확히 말하면 공유 자체는 가능하지만 공유하면 문제가 발생할 수 있습니다)
하지만 String은 불변이므로 여러 쓰레드에서 접근해도 문제가 발생하지 않습니다
-> 의존 객체를 공유할 수 있습니다
위의 예처럼 불변을 보장하면 여러 클라이언트가 의존 객체를 공유할 수 있습니다
'의존 객체가 불변이라면, 여러 클라이언트가 의존 객체들을 공유할 수 있다' 의 의미를 좀 더 Deep하게 이야기해보고 싶네요. 제가 생각한 것들이 맞는지도 궁금하고요!
아래 예시를 기준으로 이야기해보겠습니다.
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
public boolean isValid(String word) {...}
public List<String> suggestions(String typo) {...}
}
- 인스턴스 변수로 선언된 의존 객체(
private final Lexicon dictionary;
)는 메모리의 Heap 영역에 생성된다. - 인스턴스 변수이므로
SpellChecker
의 객체를 생성할 때마다 새로 생성된다. - '여러 클라이언트'라는 말을 "여러 요청이 들어온다"고 해석했을 때 여러 요청마다 스레드가 생긴다.
- 스레드는 각자의
Stack
이 생기며 메모리의Heap
과Method Area
영역은 공유된다. Heap
영역은 공유되므로 여러 개의 스레드는 인스턴스 변수로 선언된 의존 객체에 접근할 수 있다.- 의존 객체가 불변이 아니라면 스레드는 의존 객체에 접근해서 상태를 바꿀 수 있다.
- 의존 객체가 불변이라면 스레드는 의존 객체에 접근해서 필드값을 바꿀 수 없다.
즉, 의존 객체들은 Heap 영역에 있기 때문에 항상 공유가 됩니다.
의존 객체가 불변이면 공유할 수 있고, 의존 객체가 불변이 아니면 공유를 못하는 게 아닙니다.
개인적으로는 '의존 객체가 불변이라면, 여러 클라이언트가 의존 객체들을 공유할 수 있다'라는 말보다 '의존 객체가 불변이라면 여러 클라이언트가 공유하더라도 문제가 발생하지 않는다'가 맞는 것 같네요.
잘못된 내용이 있다면 피드백해주시면 감사하겠습니다.
저도 호빈님 의견과 같은 생각인데요
Java 언어 자체에서 불변 immutable
이 아니라면 의존할 수 없다 프로퍼티나 메서드에서 사용할 수 없다로 해석하면 되겠죠?
라고 강제하지 않았기 때문에 가변 mutable
객체라도 여러 객체에서 공유는 가능하다고 할 수 있을거 같네요.
다만, 가변 객체는 동시성 이슈에서 자유롭지 못하잖아요..! 멀티스레드 환경에서 여러 스레드가 하나의 객체를 동시에 다루는 경우에 데이터 무결성 보장이 쉽지 않죠. 이를 해결할 수 있는 방법 중 가장 간단한 방법이 불변 객체를 사용하는 방법이고 가장 간단하기 때문에 널리 쓰이는게 아닌가 생각을 합니다 ㅎㅎ