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?