초기화 지연
· 필드 초기화를 실제로 그 값이 쓰일 때 까지 미루는 것.
이 기법은 static필드와 객체 필드에 모두 적용가능하다.
초기화 지연을 적용할 때 따라야할 최고의 지침은 “정말로 필요하지 않으면 하지 마라”는 것이다.
초기화 지연은 양날의 검이다.
· 초기화 지연 시 클래스를 초기화 하고 개체를 생성하는 비용은 줄일 수 있다.
· 초기화 지연 시 필드 사용 비용은 증가된다.
필드 사용빈도가 낮고 초기화 비용이 높다면 쓸만하다는 뜻이다.
다중 스레드 환경에서 초기화 지연기법을 구현하는것은 까다롭다.
· 두개 이상의 스레드가 그런 필드를 공유할 때는 반드시 적정한 동기화를 해 주어야 하며, 그렇지 않으면 심각한 버그가 생길 수 있다.
대부분의 경우, 지연된 초기화를 하느니 일반 초기화를 하는것이 낫다.
// 객체 필드를 초기화하는 일반적인 방법
private final FieldType field = computeFieldValue();
초기화 순환성문제를 해소하기 위해서 초기화를 지연시키는 경우에는 동기화된 접근자를 사용하라.
// 동기화된 접근자를 사용한 객체 필드 초기화 지연 방법
private FieldType field;
synchronized FieldType getField(){
if(field == null)
field = computeFieldValue();
return field;
}
성능 문제 때문에 정적 필드 초기화를 지연시키고 싶을 때는 초기화 지연 담당 클래스숙어를 적용하라.
// 정적 필드에 대한 초기화 지연 담당 클래스 숙어
private static class FieldHolder{
static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }
· getField를 동기화 하지 않아도 되며 초기화를 지연시켜도 메서드 이용비용이 증가하지 않는다.
성능 문제 때문에 객체 필드 초기화를 지연시키고 싶다면 이중 검사숙어를 사용하라.
// 이중 검사 패턴을 통해 객체 필드를 초기화를 지연시키는 숙어
private volatile FieldType field;
FieldType getField(){
FieldType result = field;
if( result == null ) { // 첫 번째 검사(락 없음)
synchronized(this) {
result = field;
if(result == null) // 두 번째 검사 (락)
field = result = computeFieldValue();
}
}
return result;
}
오늘날 이중 검사 숙어는 객체 필드 초기화를 지연시키고자 할 때 사용하는 숙어가 되었다.
여러번 초기화 되어도 상관 없는 객체 필드 초기화를 지연시키고 싶을 때가 있다.
이중 검사 숙어의 변종 가운데 주의해야할 두가지
1. 이중검사 숙어의 두번째검사를 없애라
2. 단일 검사 숙어를 주의해라
// 단일 검사 숙어 - 필드가 여러번 초기화 될 수 있다.
private volatile fieldType field;
private FieldType getField(){
FieldType result = field;
if(result == null)
field = result = computeFieldValue();
return result;
}
· 모든 스레드가 필드 값을 재계산하더라도 상관없고 필드 자료형이 long이나 double아닌 기본 자료형인 경우에는 단일 검사 숙어에서 volatile키워드는 빼도 된다.
ㄴ 경쟁적 단일 검사 숙어
ㄴ 필드 접근 성능을 올려주나 초기화가 여러번 이뤄질 가능성이 있다.
결론
· 대부분의 필드 초기화는 지연시키지 않아야 한다.
· 하지만 필드 초기화를 지연해야 한다면 객체 필드에는 이중 검사, 정적 필드에는 초기화 지연담당 클래스, 단일 검사 숙어 등을 고려하라.
'IT > Programming' 카테고리의 다른 글
<Effective Java> RULE 69 wait이나 notify대신 병행성 유틸리티를 이용하라 (0) | 2023.04.26 |
---|---|
<Effective Java> RULE 70 스레드 안전성에 대해 문서로 남겨라 (0) | 2023.04.26 |
<Effective Java> RULE 72 스레드 스케줄러에 의존하지 마라 (0) | 2023.04.25 |
<Effective Java> RULE 73 스레드 그룹은 피하라 (0) | 2023.04.25 |
<Effective Java> RULE 74 Serializable 인터페이스를 구현할 때는 신중하라 (0) | 2023.04.25 |