[Effective Java] 아이템 83. 지연 초기화는 신중히 사용하라

2022. 12. 26. 22:07· BE/Java
목차
  1. 아이템 83. 지연 초기화는 신중히 사용하라
반응형

EFFECTIVE JAVA(이펙티브 자바)

 

이 포스팅에서 작성하는 내용은 EFFECTIVE JAVA(이펙티브자바) 에서 발췌하였습니다.


아이템 83. 지연 초기화는 신중히 사용하라

 

지연 초기화(lazy initialization)

  • 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법
  • 값이 전혀 쓰이지 않으면, 초기화도 절대 일어나지 않는다.
  • 정적 필드와 인스턴스 필드 모두 적용 가능하다.
  • 주로 최적화 용도로 쓰이지만, 클래스와 인스턴스 초기화 때 발생하는 위험한 순환 문제를 해결하는 효과도 있다.
  • 지연 초기화는 양날의 검이다.
    • 클래스 혹은 인스턴스 생성 시 초기화 비용은 줄어들지만 지연 초기화하는 필드에 접근하는 비용은 커진다.
    • 지연 초기화를 하는 필드 중 결국 초기화가 이뤄지는 비율에 따라, 실제 초기화에 드는 비용에 따라, 초기화된 각 필드를 얼마나 빈번히 호출하느냐에 따라 지연 초기화가 실제로는 성능을 느려지게 할 수도 있다.
  • 지연 초기화가 필요한 경우
    • 해당 클래스의 인스턴스 중 그 필드를 사용하는 인스턴스의 비율이 낮은 반면, 그 필드를 초기화하는 비용이 클 때
  • 멀티 스레드 환경에서는 지연 초기화를 하기 까다롭다.
    • 지연 초기화하는 필드를 둘 이상의 스레드가 공유한다면 어떤 형태로든 반드시 동기화해야 한다.
  • 대부분의 상황에서 일반적인 초기화가 지연 초기화보다 낫다

 

 

ex 1) 인스턴스 필드를 선언할 때 수행하는 일반적인 초기화 예시

private final FieldType field = computeFieldValue();
  • final 한정자를 사용했다.

 

 

ex 2) synchronized 접근자를 이용한 인스턴스 필드의 지연 초기화 예시

private FieldType field;
private synchronized FieldType getField() {
  if (field == null)
    field = computeFieldValue();
  return field;
}
  • 지연 초기화가 초기화 순환성을 깨뜨릴 것 같으면 synchronized 접근자를 사용하자.
  • 이상의 두 관용구는 정적 필드에도 똑같이 적용된다.
  • 물론, 필드와 접근자 메서드 선언에 static 한정자를 추가해야한다.

 

 

ex 3) 정적 필드용 지연 초기화 홀더 클래스 관용구 예시

private static class FieldHolder {
  static final FieldType field = computeFieldValue();
}

private static FieldType getField() { return FieldHolder.field; }
  • 성능 때문에 정적 필드를 지연 초기화해야 한다면 지연 초기화 홀더 클래스 관용구를 사용하자
  • 클래스는 클래스가 처음 쓰일 때 비로소 초기화된다는 특성을 이용한 관용구이다.
  • getField가 처음 호출되는 순간 FieldHolder.field가 처음 읽히면서, 비로소 FieldHolder 클래스 초기화를 촉발한다.
  • getField 메서드가 필드에 접근하면서 동기화를 전혀하지 않으니 성능이 느려질 거리가 없다.
  • 일반적인 VM은 오직 클래스를 초기화할 때만 필드 접근을 동기화한다.
  • 클래스 초기화가 끝난 후에는 VM이 동기화 코드를 제거하여, 그 다음부터는 아무런 검사나 동기화 없이 필드에 접근한다.

 

 

ex 4) 인스턴스 필드 지연 초기화용 이중검사 관용구 예시

private volatile FieldType field;

private FieldType getField4() {
  FieldType result = field;
  if (result != null)    // 첫 번째 검사 (락 사용 안 함)
    return result;

  synchronized(this) {
    if (field == null) // 두 번째 검사 (락 사용)
      field = computeFieldValue();
    return field;
  }
}
  • 성능 때문에 인스턴스 필드를 지연 초기화해야 한다면 이중검사 관용구를 사용하자
  • 이 관용구는 초기화된 필드에 접근할 떄 동기화 비용을 없애준다.
  • 필드의 값을 두 번 검사하는 방식으로, 한 번은 동기화 없이 검사하고, 두 번째는 동기화하여 검사한다.
  • 두 번째 검사에서도 필드가 초기화되지 않았을 때만 필드를 초기화한다.
  • 필드가 초기화된 후로는 동기화하지 않으므로 해당 필드는 반드시 volatile로 선언해야한다.
  • result 지역 변수가 필요한 이유
    • 필드가 이미 초기화된 상황(일반적)에서는 그 필드를 딱 한 번만 읽도록 보장하는 역할

 

 

ex 5) 단일 검사 관용구 (초기화가 중복해서 일어날 수 있다)

private volatile FieldType field;

private FieldType getField() {
  FieldType result = field;
  if (result == null)
    field = result = computeFieldValue();
  return result;
}

private static FieldType computeFieldValue() {
  return new FieldType();
}
  • 이중검사의 변종 관용구이다.
  • 반복해서 초기화해도 상관없는 인스턴스 필드를 지연 초기화하는 경우, 초기화가 중복해서 일어날 수 있다.

 

 

정리

  • 대부분의 필드는 지연시키지 않고 바로 초기화해야 한다.
  • 성능 때문에 혹은 위험한 초기화 순환을 막기 위해서 지연초기화를 쓴다면 올바르게 사용해야 한다.
  • 인스턴스 필드에는 이중검사 관용구를, 정적 필드에는 지연 초기화 홀더 클래스 관용구를 사용하자.
  • 반복해 초기화해도 괜찮은 인스턴스에는 단일검사 관용구도 고려해보자.
반응형

'BE > Java' 카테고리의 다른 글

[Effective Java] 아이템 85. 자바 직렬화의 대안을 찾으라  (0) 2022.12.28
[Effective Java] 아이템 84. 프로그램의 동작을 스레드 스케줄러에 기대지 말라  (1) 2022.12.27
[Effective Java] 아이템 82. 스레드 안정성 수준을 문서화하라  (0) 2022.12.23
[Effective Java] 아이템 81. wait와 notify보다는 동시성 유틸리티를 애용하라  (0) 2022.12.22
[Effective Java] 아이템 80. 스레드보다는 실행자, 태스크, 스트림을 이용하라  (0) 2022.12.21
  1. 아이템 83. 지연 초기화는 신중히 사용하라
'BE/Java' 카테고리의 다른 글
  • [Effective Java] 아이템 85. 자바 직렬화의 대안을 찾으라
  • [Effective Java] 아이템 84. 프로그램의 동작을 스레드 스케줄러에 기대지 말라
  • [Effective Java] 아이템 82. 스레드 안정성 수준을 문서화하라
  • [Effective Java] 아이템 81. wait와 notify보다는 동시성 유틸리티를 애용하라
멍목
멍목
개발 관련 새롭게 알게 된 지식이나 좋은 정보들을 메모하는 공간입니다.
반응형
멍목
김멍목의 개발블로그
멍목
전체
오늘
어제
  • 분류 전체보기 (514)
    • BE (190)
      • Spring (21)
      • Java (141)
      • Kotlin (6)
      • JPA (22)
    • FE (33)
      • Javascript (16)
      • Typescript (0)
      • React (5)
      • Vue.js (9)
      • JSP & JSTL (3)
    • DB (32)
      • Oracle (22)
      • MongoDB (10)
    • Algorithm (195)
    • Linux (8)
    • Git (6)
    • etc (42)
    • ---------------------------.. (0)
    • 회계 (4)
      • 전산회계 2급 (4)
    • 잡동사니 (2)

블로그 메뉴

  • 홈
  • 관리

공지사항

인기 글

태그

  • 전산회계 2급 준비
  • 알고리즘 공부
  • vue3 공부
  • 코틀린
  • 코테 공부
  • Oracle
  • 자바 테스팅 프레임워크
  • 더 자바 Java 8
  • JPA 공부
  • 알고리즘공부
  • 자바 공부
  • 자기개발
  • java 8
  • MongoDB 공부
  • 이펙티브 자바
  • 이펙티브자바
  • MongoDB 기초부터 실무까지
  • 자기공부
  • JPA
  • 자바 개발자를 위한 코틀린 입문
  • 더 자바 애플리케이션을 테스트하는 다양한 방법
  • 코테공부
  • MongoDB with Node.js
  • 프로젝트로 배우는 Vue.js 3
  • 자기 개발
  • 자기 공부
  • Java to Kotlin
  • 자바공부
  • junit5
  • Effective Java

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.0
멍목
[Effective Java] 아이템 83. 지연 초기화는 신중히 사용하라
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.