-
item 83 지연 초기화는 신중히 사용하라책/이펙티브 자바 2022. 4. 25. 15:48
ITEM 83 지연 초기화는 신중히 사용하라
지연 초기화(lazy initialization)는 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법이다
- 값이 전혀 쓰이지 않으면 초기화도 결코 일어나지 않는다
- 이 기법은 정적 필드와 인스턴스 필드 모두에 사용할 수 있다
- 지연 초기화는 주로 최적화 용도로 쓰이며 클래스와 인스턴스 초기화 때 발생하는 위험한 순환 문제를 해결하는 효과도 있다
- 다른 모든 최적화와 마찬기로 필요할 때까지는 하지 않는게 좋으며 지연초기화는 양날의 검이다
- 클래스 혹은 인스턴스 생성시 초기화 비용은 줄지만 그 대신 지연 초기화하는 필드에 접근하는 비용은 커진다
- 지연 초기화하려는 필드 중 결국 초기화가 이뤄지는 비율, 실제 초기화에 드는 비용, 초기화된 각 필드를 얼마나 빈번히 호출 하느냐에 따라 지연초기화가 실제로는 성능을 느려지게 할 수도 있다
지연 초기화가 필요한 경우
- 위와 같은 문제점이 있지만 지연 초기화가 필요한 경우가 있다
- 해당 클래스의 인스턴스 중 그 필드를 사용하는 인스턴스의 비율이 낮지만 그 필드를 초기화 하는 비용이 크다면 지연 초기화가 제 역할을 해줄것이다
- 정말 위 조건을 만족하는지 알아보려면 지연초기화 적용 전 후의 성능을 측정하여 비교해봐야한다
멀티스레드 환경에서는 지연 초기화를 하기가 까다롭다
- 지연 초기화하는 필드를 둘 이상의 스레드가 공유한다면 어떤 형태든 반드시 동기화해야 한다
- 아니면 심각한 버그가 발생할 수 있다
대부분의 상황에서 일반적인 초기화가 지연 초기화보다 낫다
인스턴스 필드를 초기화 하는 일반적인 방법 private final FieldType field = computeFieldValue(); 지연 초기화가 초기화 순환성(initialization circularity)을 깨뜨릴 것 같으면 synchronized를 단 접근자를 사용하자 이게 가장 간단하고 명확하다 인스턴스 필드의 지연 초기화 - synchronized 접근자 방식 private FieldType field; private synchronized FieldType getField() { if (field == null) field = computeFieldValue(); return field; } 두 관용구는 정적 필드에도 똑같이 적용된다 (물론 필드와 접근자 메서드 선언에 static 한정자를 추가해야 한다)
성능 때문에 정적 필드를 지연 초기화해야 한다면 지연 초기화 홀더 클래스(lazy initialization holder class) 관용구를 사용하자
- 클래스는 클래스가 처음 쓰일 때 비로소 초기화 된다는 특성을 이용한 관용구다
성능 때문에 인스턴스 필드를 지연 초기화해야 한다면 이중검사(double-check) 관용구를 사용하라
- 이 관용구는 초기화된 필드에 접근할 때의 동기화 비용을 없애준다
- 이름에서 알 수 있듯이 필드의 값을 두 번 검사하는 방식이며 한번은 동기화 없이 검사, 필드가 아직 초기화 되지 않았다면 두번째는 동기화해서 검사한다
- 두번째 검사에도 필드가 초기화되지 않았을 때만 필드를 초기화 한다
- 필드가 초기화된 후로는 동기화를 안하기 때문에 해당 필드는 반드시 volatile로 선언해야 한다
- 이중 검사에는 두가지 변종이 있다
- 단일검사 관용구
- 가끔 반복해서 초기화해도 상관없는 인스턴스 필드를 지연 초기화해야 하는 경우가 있는데 이런 경우 이중검사에서 두 번째 검사를 생략 할 수 있다
- 짜릿한 단일검사 관용구
- 모든 스레드가 필드의 값을 다시 계산해도 되며 필드의 타입이 long과 double을 제외한 다른 기본 타입이면 단일검사의 필드 선언에서 volatile 한정자를 없애도 된다
- 어떤 환경에서는 필드 접근 속도를 높여 주지만 초기화가 스레드당 최대 한 번 더 이뤄질 수 있으며 거의 안 쓴다
- 단일검사 관용구
대부분의 필드는 지연시키지 말고 곧바로 초기화해야 한다
성능 때문에 혹은 위험한 초기화 순환을 막기 위해 꼭 지연 초기화를 써야 한다면 올바른 지연 초기화 기법을 사용하자
인스턴스 필드에는 이중검사 관용구를 정적 필드에는 지연 초기화 홀더 클래스 관용구를 사용하자
반복해 초기화해도 괜찮은 인스턴스 필드에는 단일검사 관용구도 고려하자
'책 > 이펙티브 자바' 카테고리의 다른 글
item 85 자바 직렬화의 대안을 찾으라 (0) 2022.04.26 item 84 프로그램의 동작을 스레드 스케줄러에 기대지 말라 (0) 2022.04.25 item 82 스레드 안정성 수준을 문서화하라 (0) 2022.04.25 item 81 wait와 notify보다는 동시성 유틸리티를 애용하라 (0) 2022.04.25 item 80 스레드보다는 실행자, 태스크, 스트림을 애용하라 (0) 2022.04.23