Meet-Coder-Study / book-effective-java

📔 이펙티브 자바 스터디 저장소

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

아이템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) {...}
}
  1. 인스턴스 변수로 선언된 의존 객체(private final Lexicon dictionary;)는 메모리의 Heap 영역에 생성된다.
  2. 인스턴스 변수이므로 SpellChecker의 객체를 생성할 때마다 새로 생성된다.
  3. '여러 클라이언트'라는 말을 "여러 요청이 들어온다"고 해석했을 때 여러 요청마다 스레드가 생긴다.
  4. 스레드는 각자의 Stack이 생기며 메모리의HeapMethod Area 영역은 공유된다.
  5. Heap 영역은 공유되므로 여러 개의 스레드는 인스턴스 변수로 선언된 의존 객체에 접근할 수 있다.
  6. 의존 객체가 불변이 아니라면 스레드는 의존 객체에 접근해서 상태를 바꿀 수 있다.
  7. 의존 객체가 불변이라면 스레드는 의존 객체에 접근해서 필드값을 바꿀 수 없다.

즉, 의존 객체들은 Heap 영역에 있기 때문에 항상 공유가 됩니다.
의존 객체가 불변이면 공유할 수 있고, 의존 객체가 불변이 아니면 공유를 못하는 게 아닙니다.

개인적으로는 '의존 객체가 불변이라면, 여러 클라이언트가 의존 객체들을 공유할 수 있다'라는 말보다 '의존 객체가 불변이라면 여러 클라이언트가 공유하더라도 문제가 발생하지 않는다'가 맞는 것 같네요.

잘못된 내용이 있다면 피드백해주시면 감사하겠습니다.

저도 호빈님 의견과 같은 생각인데요

Java 언어 자체에서 불변 immutable이 아니라면 의존할 수 없다 프로퍼티나 메서드에서 사용할 수 없다로 해석하면 되겠죠? 라고 강제하지 않았기 때문에 가변 mutable 객체라도 여러 객체에서 공유는 가능하다고 할 수 있을거 같네요.

다만, 가변 객체는 동시성 이슈에서 자유롭지 못하잖아요..! 멀티스레드 환경에서 여러 스레드가 하나의 객체를 동시에 다루는 경우에 데이터 무결성 보장이 쉽지 않죠. 이를 해결할 수 있는 방법 중 가장 간단한 방법이 불변 객체를 사용하는 방법이고 가장 간단하기 때문에 널리 쓰이는게 아닌가 생각을 합니다 ㅎㅎ