lazy
์ฝํ๋ฆฐ lazy
ํ๋กํผํฐ: ์ปดํ์ผ๋ ์ฝ๋ ๋ถ์
lazy
ํ๋กํผํฐ: ์ปดํ์ผ๋ ์ฝ๋ ๋ถ์lazy
ํ๋กํผํฐ๋ ๋จ์ํ ๋ฌธ๋ฒ์ ์คํ์ด ์๋๋๋ค. ์ปดํ์ผ๋ฌ๋ ์ด ์ฝ๋๋ฅผ ๋ฐํ์์ ์ง์ฐ ์ด๊ธฐํ ๋ก์ง์ ์ํํ๋ ์ค์ ๋ฐ์ดํธ์ฝ๋๋ก ๋ณํํฉ๋๋ค. ์ด ๊ณผ์ ์ ์ดํดํ๋ฉด lazy
์ ๋์ ์๋ฆฌ์ ์ฑ๋ฅ ํน์ฑ์ ๋ ๊น์ด ํ์
ํ ์ ์์ต๋๋ค.
1. lazy
์ปดํ์ผ ๊ณผ์ ์ ํต์ฌ
lazy
์ปดํ์ผ ๊ณผ์ ์ ํต์ฌ์ฝํ๋ฆฐ ์ปดํ์ผ๋ฌ๋ by lazy { ... }
๊ตฌ๋ฌธ์ ๋ง๋๋ฉด, lazy
๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ์ํ ๋ณด์กฐ ํ๋(backing field)๋ฅผ ์์ฑํฉ๋๋ค. ์ด ํ๋๋ Lazy<T>
ํ์
์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ฉฐ, ์ด๊ธฐํ ๋๋ค์์ ์ด ๊ฐ์ฒด ๋ด๋ถ์ ์บก์ฒ๋ฉ๋๋ค.
// ์๋ณธ ์ฝํ๋ฆฐ ์ฝ๋
class MyClass {
val myLazyValue: String by lazy {
"Hello, World!"
}
}
์ ์ฝ๋๋ JVM ๋ฐ์ดํธ์ฝ๋๋ก ์ปดํ์ผ๋ ๋, ๋ค์๊ณผ ์ ์ฌํ ์๋ฐ ์ฝ๋๋ก ์ญ์ปดํ์ผ๋์ด ๋ณด์ผ ์ ์์ต๋๋ค. (์ค์ ์์ฑ๋๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์์ฌ ์ฝ๋๋ก ํํํ ๊ฒ์)
// ์ปดํ์ผ๋ ์๋ฐ ์์ฌ ์ฝ๋
public final class MyClass {
// myLazyValue$delegate ํ๋ ์์ฑ. Lazy ๊ฐ์ฒด๋ฅผ ์ ์ฅ
private final Lazy myLazyValue$delegate;
// myLazyValue ํ๋กํผํฐ์ ๊ฒํฐ(getter)
public final String getMyLazyValue() {
// ๋ธ๋ฆฌ๊ฒ์ดํธ ๊ฐ์ฒด์ value ์์ฑ์ ํตํด ์ค์ ๊ฐ์ ์ ๊ทผ
return (String)this.myLazyValue$delegate.getValue();
}
public MyClass() {
// lazy ํจ์๋ฅผ ํธ์ถํ์ฌ Lazy ๊ฐ์ฒด ์ด๊ธฐํ
// LazyThreadSafetyMode.SYNCHRONIZED๊ฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉ๋จ
this.myLazyValue$delegate = LazyKt.lazy(null, new MyClass$$special$$inlined$myLazyValue$1());
}
}
MyClass
์ ์ธ์คํด์ค๊ฐ ์์ฑ๋ ๋, myLazyValue
์์ฒด๊ฐ ๋ฐ๋ก ์ด๊ธฐํ๋๋ ๊ฒ์ด ์๋๋ผ, Lazy
๊ฐ์ฒด๋ฅผ ์์ฑํ๋ lazy
ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค. ์ด Lazy
๊ฐ์ฒด๋ ์ด๊ธฐํ ๋ก์ง์ ๋ด๊ณ ์๋ ๋๋ค(์ปดํ์ผ๋ฌ๊ฐ ์์ฑํ MyClass$$special$$inlined$myLazyValue$1
ํด๋์ค)์ ๋ํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๋๋ค.
LazyKt.lazy
LazyKt.lazy
๋ ์ฝํ๋ฆฐ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ ์ต์์(top-level) ํจ์๋ก, by lazy { ... }
๊ตฌ๋ฌธ์ ์ฒ๋ฆฌํ๋ ํต์ฌ ์ญํ ์ ๋ด๋นํฉ๋๋ค. ์ปดํ์ผ๋ฌ๋ by lazy
๊ตฌ๋ฌธ์ ์ด ํจ์์ ๋ํ ํธ์ถ๋ก ๋ณํํ์ฌ ์ง์ฐ ์ด๊ธฐํ ๋ก์ง์ ๊ตฌํํฉ๋๋ค.
LazyKt.lazy
์ ์ญํ
LazyKt.lazy
์ ์ญํ LazyKt.lazy
๋ ์ด๊ธฐํ ๋ก์ง์ ๋ด์ ๋๋ค์์ ์ธ์๋ก ๋ฐ์ Lazy<T>
์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๊ตฌํ์ฒด๋ ๋ค์ ๋ ๊ฐ์ง ์ฃผ์ ์ญํ ์ ์ํํฉ๋๋ค.
์ด๊ธฐํ ๋ก์ง ์บก์ฒ:
lazy
์ ์ ๋ฌ๋ ๋๋ค์(์ด๊ธฐํ ๋ธ๋ก)์ ๊ฐ์ฒด ๋ด๋ถ์ ์บก์ฒํ์ฌ ์ ์ฅํฉ๋๋ค.์ง์ฐ ์ด๊ธฐํ ๊ด๋ฆฌ: ์ด ๊ฐ์ฒด๋
getValue()
๋ฉ์๋๋ฅผ ํตํด ํ๋กํผํฐ์ ์ ๊ทผํ ๋ ๋๋ค์์ ์คํํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํฉ๋๋ค.
LazyKt.lazy
์ ์ปดํ์ผ ๊ณผ์
LazyKt.lazy
์ ์ปดํ์ผ ๊ณผ์ // SynchronizedLazyImpl (๊ธฐ๋ณธ๊ฐ)
// ์ค๋ ๋ ์์ ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด synchronized ๋ธ๋ก์ ์ฌ์ฉํฉ๋๋ค.
private class SynchronizedLazyImpl<T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer // ์ด๊ธฐํ ๋๋ค
@Volatile private var _value: Any? = UNINITIALIZED_VALUE // ์ค์ ๊ฐ์ ์ ์ฅํ๋ ํ๋
private val lock = lock ?: this
override val value: T
get() {
// ์ด ๋ธ๋ก์์๋ง ์ด๊ธฐํ๊ฐ ์งํ๋๋๋ก ๋๊ธฐํ
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
_v2 as T
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null // ์ด๊ธฐํ ํ ๋๋ค๋ฅผ GC ๋์์ผ๋ก ๋ง๋ฆ
typedValue
}
}
}
}
// SafePublicationLazyImpl (PUBLICATION ๋ชจ๋)
// ๋๊ธฐํ ์ค๋ฒํค๋๋ฅผ ์ค์ด๊ธฐ ์ํด ์ ๊ธ ์๋(lock-free) ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํฉ๋๋ค.
private class SafePublicationLazyImpl<T>(initializer: () -> T) : Lazy<T> {
@Volatile private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
val value = _value
if (value !== UNINITIALIZED_VALUE) {
return value as T
}
// ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ด ๋ธ๋ก์ ์ง์
ํ ์ ์์
val initializer = this.initializer
if (initializer != null) {
val typedValue = initializer()
// CAS(Compare-and-Swap) ์ฐ์ฐ๊ณผ ์ ์ฌํ ๋ก์ง์ผ๋ก
// _value๊ฐ UNINITIALIZED_VALUE์ผ ๋๋ง ๊ฐ์ ๋ฎ์ด์
if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, typedValue)) {
this.initializer = null
return typedValue
}
}
// ๋ค๋ฅธ ์ค๋ ๋๊ฐ ๋จผ์ ์ด๊ธฐํํ์ ๊ฒฝ์ฐ
return _value as T
}
}
// UnsafeLazyImpl (NONE ๋ชจ๋)
// ๋๊ธฐํ ๋ก์ง์ด ์ ํ ์์ด ๋จ์ผ ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ์ฅ ๋น ๋ฆ
๋๋ค.
private class UnsafeLazyImpl<T>(initializer: () -> T) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
val initializer = initializer
if (initializer != null) {
val typedValue = initializer()
_value = typedValue
this.initializer = null
return typedValue
}
return _value as T
}
}
LazyKt.lazy
์ ์ธ๋ถ ๋์
LazyKt.lazy
์ ์ธ๋ถ ๋์LazyKt.lazy
ํจ์๋ LazyThreadSafetyMode
์ ๋ฐ๋ผ ๋ด๋ถ์ ์ผ๋ก ๋ค๋ฅธ Lazy
๊ตฌํ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
LazyThreadSafetyMode.SYNCHRONIZED
(๊ธฐ๋ณธ๊ฐ):lazy()
ํจ์๋SynchronizedLazyImpl
ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ํด๋์ค๋synchronized
๋ธ๋ก์ ์ฌ์ฉํ์ฌ ์ด๊ธฐํ ๋ก์ง์ด ํ ๋ฒ๋ง ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ ๊ทผํ๋ฉดgetValue()
๋ ์ ๊ธ(lock)์ ์ป์ ์ฒซ ๋ฒ์งธ ์ค๋ ๋๋ง ์ด๊ธฐํ๋ฅผ ์งํํฉ๋๋ค.LazyThreadSafetyMode.PUBLICATION
:lazy(LazyThreadSafetyMode.PUBLICATION, ...)
ํธ์ถ ์SafePublicationLazyImpl
์ธ์คํด์ค๊ฐ ๋ฐํ๋ฉ๋๋ค. ์ด๋ ์ ๊ธ ์์ด(lock-free) ์ด๊ธฐํ ๋ก์ง์ ์คํํ๋ฉฐ, ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ด๊ธฐํ๋ฅผ ์๋ํ ์ ์์ต๋๋ค. ๋จผ์ ์๋ฃ๋ ์ค๋ ๋์ ๊ฒฐ๊ณผ๊ฐ ์ต์ข ๊ฐ์ผ๋ก ์ฑํ๋๊ณ , ๋๋จธ์ง๋ ํ๊ธฐ๋ฉ๋๋ค.LazyThreadSafetyMode.NONE
:lazy(LazyThreadSafetyMode.NONE, ...)
ํธ์ถ ์UnsafeLazyImpl
์ธ์คํด์ค๊ฐ ๋ฐํ๋ฉ๋๋ค. ์ด๋ ์ค๋ ๋ ์์ ์ฑ์ ์ ํ ๊ณ ๋ คํ์ง ์์ผ๋ฏ๋ก ๋จ์ผ ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ์ฅ ํจ์จ์ ์ ๋๋ค.
2. LazyThreadSafetyMode
์ ๋ฐ๋ฅธ ์ค์ ๋์ ์ฐจ์ด
LazyThreadSafetyMode
์ ๋ฐ๋ฅธ ์ค์ ๋์ ์ฐจ์ดLazy<T>
๊ตฌํ์ฒด๋ LazyThreadSafetyMode
์ ๋ฐ๋ผ ๋ด๋ถ ๋ก์ง์ด ๋ฌ๋ผ์ง๋๋ค.
SYNCHRONIZED (๊ธฐ๋ณธ๊ฐ):
getValue()๊ฐ ํธ์ถ๋ ๋, synchronized ๋ธ๋ก์ด๋ ReentrantLock ๊ฐ์ **์ ๊ธ(lock)**์ ์ฌ์ฉํ์ฌ ๋๋ค์์ด ํ ๋ฒ๋ง ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ getValue()๋ฅผ ํธ์ถํด๋, ์ฒซ ๋ฒ์งธ ์ค๋ ๋๋ง ๋๋ค์์ ์คํํ๊ณ ๋๋จธ์ง๋ ๋๊ธฐํ๊ฒ ๋ฉ๋๋ค. ์ด๊ธฐํ๊ฐ ์๋ฃ๋๋ฉด _value ํ๋์ ๊ฒฐ๊ณผ๊ฐ ์ ์ฅ๋๊ณ , ์ดํ์๋ ๋๋ค์ ์คํ ์์ด ์ฆ์ _value๋ฅผ ๋ฐํํฉ๋๋ค.
PUBLICATION:
getValue()๋ ์ ๊ธ์ ์ฌ์ฉํ์ง ์์ต๋๋ค. ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ ๊ทผํ๋ฉด ๋ชจ๋ ๋๋ค์์ ์คํํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ค์์ ๊ฒฐ๊ณผ๊ฐ _value ํ๋์ ์ฐ์ฌ์ง๋ ์์ ์ ์์์ ์ธ compare-and-swap (CAS) ์ฐ์ฐ์ ์ฌ์ฉํฉ๋๋ค. ์ด ์ฐ์ฐ์ _value๊ฐ ์์ง ์ด๊ธฐํ๋์ง ์์์ ๋๋ง ๊ฐ์ ๋ฎ์ด์๋๋ค. ๋ฐ๋ผ์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ด๊ธฐํํ๋๋ผ๋, ์ต์ข ์ ์ผ๋ก๋ ํ๋์ ๊ฐ๋ง _value์ ์ ์ฅ๋ฉ๋๋ค. ์ด๋ ์ค๋ ๋ ๊ฐ ๋๊ธฐํ ์ค๋ฒํค๋๋ฅผ ์ค์ฌ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
NONE:
getValue()๋ ์๋ฌด๋ฐ ๋๊ธฐํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ง ์์ต๋๋ค. ์์ํ ๋จ์ผ ์ค๋ ๋ ํ๊ฒฝ์ ๊ฐ์ ํ๋ฉฐ, _value ํ๋๊ฐ null์ธ์ง ํ์ธํ๊ณ null์ด๋ฉด ๋๋ค์์ ์คํํ์ฌ ๊ฐ์ ํ ๋นํฉ๋๋ค. ์ด ๋ชจ๋๋ ๊ฐ์ฅ ๋น ๋ฅด์ง๋ง, ์ค๋ ๋ ์์ ์ฑ์ด ๋ณด์ฅ๋์ง ์์ต๋๋ค.
3. ์ lazy
๋ val
์๋ง ์ฌ์ฉ๋ ๊น?
lazy
๋ val
์๋ง ์ฌ์ฉ๋ ๊น?lazy
๋ val
(์ฝ๊ธฐ ์ ์ฉ) ํ๋กํผํฐ์๋ง ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ๊ทธ ์ด์ ๋ lazy
์ ๋ณธ์ง์ด ๋จ ํ ๋ฒ์ ์ด๊ธฐํ๋ฅผ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์
๋๋ค. lazy
๋ ๊ฐ์ ์บ์ํ๊ณ , ์ดํ์ ๋ชจ๋ ์ ๊ทผ์ ๋ํด ๋์ผํ ์บ์๋ ๊ฐ์ ๋ฐํํฉ๋๋ค. ๋ง์ฝ var
์ lazy
๊ฐ ํ์ฉ๋๋ค๋ฉด, myLazyValue = "newValue"
์ ๊ฐ์ด ๊ฐ์ ์ฌํ ๋นํ๋ ๊ฒ์ ์ด "ํ ๋ฒ์ ์ด๊ธฐํ"๋ผ๋ lazy
์ ํต์ฌ ๊ฐ๋
๊ณผ ์ถฉ๋ํ๊ฒ ๋ฉ๋๋ค. val
์ ๋ํ lazy
๋ ๊ฒ์ผ๋ฅธ ์ฑ๊ธํค ํจํด์ ํ๋กํผํฐ ๋ฒ์ ๊ณผ ์ ์ฌํ๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
lazy
๋ ๋จ์ํ ๋ฌธ๋ฒ์ ํธ์๋ฅผ ๋์ด, ๋ฐํ์์ ์ง์ฐ ์ด๊ธฐํ ๋ก์ง์ ์ํํ๋ ๋ณต์กํ ๊ฐ์ฒด์ ๋ฐ์ดํธ์ฝ๋๋ก ๋ณํ๋ฉ๋๋ค. ํนํ LazyThreadSafetyMode
๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ์ค๋ ๋ ํ๊ฒฝ์ ๋ฐ๋ผ ์ต์ ์ ์ฑ๋ฅ ์ ๋ต์ ์ ํํ ์ ์์ต๋๋ค. lazy
๋ ๋จ์ํ ์ฝ๋๋ฅผ ์ค์ด๋ ๋๊ตฌ๊ฐ ์๋๋ผ, ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ ๋์์ ๊ณ ๋ คํ๋ ์๋์ด ๊ฐ๋ฐ์์ ํ์์ ์ธ ๋๊ตฌ์
๋๋ค.
Last updated