Item 83. Lazy Initialization

지연 μ΄ˆκΈ°ν™”λŠ” μ‹ μ€‘νžˆ μ‚¬μš©ν•˜λΌ

일반적으둜 ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™” ν•  λ•Œ μ•„λž˜μ™€ 같이 μ΄ˆκΈ°ν™”λ₯Ό ν•œλ‹€.

class Init {

    private final FieldType field = computeFieldValue();
}

ν•˜μ§€λ§Œ μ΄ˆκΈ°ν™” μ‹œμ μ„ μ²˜μŒμ— ν•˜λŠ” 것이 μ•„λ‹ˆλΌ ν•„μš”ν•œ μ‹œμ μ— ν•˜λŠ” 지연 μ΄ˆκΈ°ν™” 기법을 μ‚¬μš©ν•  수 μžˆλ‹€. λ‹€λ₯Έ μ΅œμ ν™”μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 지연 μ΄ˆκΈ°ν™”λŠ” λͺ¨λ“  μƒν™©μ—μ„œ μ„±λŠ₯을 ν–₯μƒμ‹œν‚€μ§€ μ•ŠμœΌλ©°, 였히렀 μ„±λŠ₯을 μ €ν•˜μ‹œν‚¬ μˆ˜λ„ μžˆλ‹€. 지연 μ΄ˆκΈ°ν™”λŠ” 보톡 μ•„λž˜μ™€ 같은 κ²½μš°μ— μ‚¬μš©ν•œλ‹€.

  • ν•„λ“œμ˜ μ΄ˆκΈ°ν™” λΉ„μš©μ΄ 높은 경우 μ΅œμ ν™” λͺ©μ μœΌλ‘œ μ‚¬μš©

  • μˆœν™˜ 문제λ₯Ό ν•΄κ²°ν•΄μ•Ό ν•˜λŠ” 경우

μ΄ˆκΈ°ν™” μˆœν™˜μ„±(Initialization circularity) ν•΄κ²° 방법

μ΄ˆκΈ°ν™” μˆœν™˜μ„± 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 지연 μ΄ˆκΈ°ν™”λ₯Ό μ‚¬μš©ν•˜λŠ” 경우, μ•„λž˜μ™€ 같이 synchornized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ κ°„λ‹¨ν•˜κ²Œ ν•΄κ²°ν•  수 μžˆλ‹€.

class LazyInit {

    private FieldType field;

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

μ„±λŠ₯ 문제둜 μΈν•œ 지연 μ΄ˆκΈ°ν™”(정적 ν•„λ“œ)

λ§Œμ•½ μ„±λŠ₯ 문제둜 정적 ν•„λ“œλ₯Ό 지연 μ΄ˆκΈ°ν™”ν•΄μ•Όν•˜λŠ” κ²½μš°μ—” 지연 μ΄ˆκΈ°ν™” 홀더 클래슀 κ΄€μš©κ΅¬λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. ν΄λž˜μŠ€λŠ” ν΄λž˜μŠ€κ°€ μ²˜μž„ 쓰일 λ•Œ μ΄ˆκΈ°ν™”λ˜λŠ” νŠΉμ„±μ„ μ΄μš©ν•˜μ—¬ ν•„λ“œλ₯Ό 지연 μ΄ˆκΈ°ν™”ν•˜λŠ” 방법이닀.

class LazyInit {

    private static class FieldHolder {

        static final FieldType field = computeFieldValue();
    }

    private static FieldType getField() {
        return FieldHolder.field;
    }
}

getField λ©”μ„œλ“œκ°€ 처음 호좜될 λ•Œ FieldHolder ν΄λž˜μŠ€κ°€ μ΄ˆκΈ°ν™”λ˜λ©°, λ‚΄λΆ€μ˜ field ν•„λ“œκ°€ μ΄ˆκΈ°ν™”λœλ‹€. 이 방식은 동기화 없이도 지연 μ΄ˆκΈ°ν™”λ₯Ό μˆ˜ν–‰ν•  수 μžˆμ–΄, μ„±λŠ₯이 μ €ν•˜λ  μš”μΈμ΄ μ „ν˜€ μ—†λ‹€λŠ” μž₯점이 μžˆλ‹€.

μ„±λŠ₯ 문제둜 μΈν•œ 지연 μ΄ˆκΈ°ν™”(μΈμŠ€ν„΄μŠ€ ν•„λ“œ)

μΈμŠ€ν„΄μŠ€ ν•„λ“œμ˜ κ²½μš°μ—” 이쀑검사 κ΄€μš©κ΅¬λ₯Ό μ‚¬μš©ν•΄ 지연 μ΄ˆκΈ°ν™”λ₯Ό μˆ˜ν–‰ν•  수 μžˆλ‹€. 이 방식은 ν•œ 번 μ΄ˆκΈ°ν™”λœ ν•„λ“œμ— μ ‘κ·Όν•  λ•Œ 동기화 λΉ„μš©μ„ μ—†μ• μ£ΌλŠ” 방식이닀.

class LazyInit {

    private volatile FieldType field;

    private FieldType getField() {
        FieldType result = field; // 지역 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄ ν•„λ“œλ₯Ό ν•œ 번만 읽도둝 보μž₯
        if (result != null) { // 첫 번째 검사: 락 없이 μˆ˜ν–‰
            return result; // null이 μ•„λ‹ˆλ©΄ 이미 μ΄ˆκΈ°ν™”λœ μƒνƒœμ΄λ―€λ‘œ λ°˜ν™˜
        }

        synchronized (this) { // 두 번째 검사: 락을 κ±Έκ³  μˆ˜ν–‰
            if (field == null) { // ν•„λ“œκ°€ 아직 μ΄ˆκΈ°ν™”λ˜μ§€ μ•Šμ•˜λ‹€λ©΄
                field = computeFieldValue(); // ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™”
            }
            return field; // ν•„λ“œλ₯Ό λ°˜ν™˜
        }
    }
}

volatile ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν•„λ“œλ₯Ό μ„ μ–Έν•˜μ—¬, ν•„λ“œμ— λŒ€ν•œ λͺ¨λ“  읽기/μ“°κΈ°κ°€ 메인 λ©”λͺ¨λ¦¬μ—μ„œ μˆ˜ν–‰λ˜κΈ° λ•Œλ¬Έμ— 이쀑검사 κ΄€μš©κ΅¬λ₯Ό μ‚¬μš©ν•  수 있게 λœλ‹€. 이 방식은 정적 ν•„λ“œμ—λ„ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, ꡳ이 그럴 ν•„μš” 없이 정적 ν•„λ“œμ˜ κ²½μš°μ—” 지연 μ΄ˆκΈ°ν™” 홀더 클래슀 κ΄€μš©κ΅¬λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 더 μ’‹λ‹€.

Last updated

Was this helpful?