Item 83 : 지연 초기화는 신중히 사용하라
2021. 9. 20. 13:07
지연 초기화(lazy initialization)는 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법이다.
- 그 값이 쓰이지 않으면 초기화또한 일어나지 않는다.
- 이 기법은 정적 필드와 인스턴스 필드 모두에 사용할 수 있다.
- 주로 최적화 용도로 쓰이지만, 클래스와 인스턴스 초기화 때 발생하는 위험한 순환 문제를 해결하는 효과도 있다.
- 지연 초기화의 기본 메커니즘은 ' 필요할 때 까지 하지 말라 ' 이다.
- 어떻게 보면 초기화 비용이 줄어서 좋아보이지만 접근성이 떨어져 양날의 검이 될 수 있다.
- 지연 초기화가 필요한 경우
- 해당 클래스의 인스턴스 중 그 필드를 사용하는 인스턴스의 비율이 낮은 반면, 그 필드를 초기화하는 비용이 큰 경우
- 하지만 지연 초기화 사용 전 후의 성능 체크를 해봐야한다.
대부분의 상황에서 일반적인 초기화가 지연초기화보다 낫다.
//인스턴스 필드를 초기화하는 일반적인 방법
private final FieldType field = computeFieldValue();
//지연 초기화 - synchronized 접근 방식
private FieldType field;
private synchronized FieldType getField() {
if (field == null) {
field = computeFieldValue();
}
return field;
}
//성능 때문에 정적 필드를 지연초기화해야 하는 경우에 사용하는 지연 초기화 홀더 클래스 관용구
//정적 필드용 지연 초기화 홀더 클래스 관용구
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
private static FieldType getField() { return FieldHolder.field; }
//성능 때문에 인스턴스 필드를 지연 초기화해야 한다면 이중검사 관용구를 사용하라
private volatile FieldType field;
private FieldType getField() {
FieldType result = field;
if (result != null) { // 첫 번째 검사 (락 사용 안함)
return result;
}
synchronized(this) {
if (field == null) { // 두 번째 검사 (락 사용)
field = computeFieldValue();
}
return field;
}
}
// 단일검사 관용구 - 초기화가 중복해서 일어날 수 있다.
private volatile FieldType field;
private FieldType getField() {
FieldType result = field;
if( result == null) {
field = result = computFieldValue();
}
return result;
}
정리
- 대부분의 필드는 지연시키지 말고 곧바로 초기화해야 한다.
- 사용해야 한다면 올바른 지연 초기화 기법을 사용하자
- 인스턴스 필드에는 이중검사 관용구를, 정적 필드에는 지연초기화 홀더 클래스 관용구를 사용하자
'책 > 이펙티브자바' 카테고리의 다른 글
Item 85 : 자바 직렬화의 대안을 찾으라 (0) | 2021.09.22 |
---|---|
Item 84 : 프로그램의 동작을 스레드 스케줄러에 기대지 말라 (0) | 2021.09.21 |
Item 82 : 스레드 안전성 수준을 문서화하라 (0) | 2021.09.19 |
Item 81 : wait와 notify보다는 동시성 유틸리티를 애용하라 (0) | 2021.09.19 |
Item 80 : 스레드보다는 실행자, 태스크, 스트림을 애용하라. (0) | 2021.09.17 |