Kotlin by lazy()总结

文章目录

  • [Kotlin by lazy()总结](#Kotlin by lazy()总结)
    • 概述
    • 基本用法
    • 源码分析
      • [Lazy 接口](#Lazy 接口)
      • [lazy() 函数](#lazy() 函数)
      • [SynchronizedLazyImpl 类](#SynchronizedLazyImpl 类)
      • [SafePublicationLazyImpl 类](#SafePublicationLazyImpl 类)
      • [UnsafeLazyImpl 类](#UnsafeLazyImpl 类)
      • 模式区别

Kotlin by lazy()总结

概述

by lazy() 是 Kotlin 中一种懒加载委托属性的实现方式,它允许我们定义一个属性,该属性在第一次被访问时才会被初始化,之后的访问会直接返回已初始化的值。

基本用法

kotlin 复制代码
val myLazy by lazy{
    println("计算")
    "hello"
}

fun main() {
   println(myLazy)
   println(myLazy)
}
  1. 第一次访问,输出 "计算" 和 "hello"
  2. 第二次范围,只输出 "hello"

源码分析

Lazy 接口

kotlin 复制代码
public interface Lazy<out T> {
    // 懒加载的值
    public val value: T

    // 检查值是否被初始化
    public fun isInitialized(): Boolean
}

lazy() 函数

kotlin 复制代码
// 使用SynchronizedLazyImpl,线程安全
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = 
	SynchronizedLazyImpl(initializer)

// 可以指定加载模式
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
    when (mode) {
        // 完全线程安全模式
        LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
        // 线程安全模式,使用CAS
        LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
        // 线程不安全
        LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
    }

// 可以指定锁对象
public actual fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = 
	SynchronizedLazyImpl(initializer, lock)

SynchronizedLazyImpl 类

kotlin 复制代码
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
    private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE // valatile 确保多线程的可见性
    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) {
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {
                    // 初始化值
                    val typedValue = initializer!!()
                    _value = typedValue
                    // 置空
                    initializer = null
                    // 返回值
                    typedValue
                }
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}
  1. 完全线程安全,存在锁竞争,一定程度上会影响性能。
  2. 先检查是否有值,如果有值则直接返回值。
  3. 如果没有值,进入同步代码块,再次检查是否有值,如果没有值则初始化值,完成初始化后,将initializer设置为null。

SafePublicationLazyImpl 类

kotlin 复制代码
private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
    @Volatile private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    private val final: Any = UNINITIALIZED_VALUE

    override val value: T
        get() {
            val value = _value
            if (value !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return value as T
            }

            val initializerValue = initializer
             if (initializerValue != null) {
                val newValue = initializerValue()
                // CAS:相等并交换返回true,不相等返回false
                if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
                    initializer = null
                    return newValue
                }
            }
            return _value as T
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)

    companion object {
        private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
            SafePublicationLazyImpl::class.java,
            Any::class.java,
            "_value"
        )
    }
}
  1. 无锁实现,高并发下性能好,但是初始化函数可能被多次执行。
  2. 使用 AtomicReferenceFieldUpdater 进行原子操作。
  3. 允许多线程同时执行初始化函数,使用 compareAndSet 确保只有第一个返回值被使用。
  4. 避免了锁竞争,高并发性能更好。

UnsafeLazyImpl 类

kotlin 复制代码
internal class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
    private var initializer: (() -> T)? = initializer
    private var _value: Any? = UNINITIALIZED_VALUE

    override val value: T
        get() {
            if (_value === UNINITIALIZED_VALUE) {
                _value = initializer!!()
                initializer = null
            }
            return _value as T
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}
  • 线程不安全模式,性能最好。

模式区别

模式 优点 缺点
SYNCHRONIZED 完全线程安全 存在锁竞争,可能影响性能
PUBLICATION CAS无锁,高并发性能更好 初始化函数可能被多次执行
NONE 性能最高 线程不安全
相关推荐
松仔log7 小时前
Kotlin中级——callbackFlow
java·前端·kotlin
zh_xuan7 小时前
kotlin常见面试题
开发语言·kotlin·面试题
mmsx7 小时前
耳切法切带洞多边形:论文能跑通,真实数据为什么崩
android·kotlin
Kapaseker9 小时前
Kotlin 又要加语法糖了:这次轮到 if-else
android·kotlin
雨白1 天前
从原理到实践:使用 Kotlin KSP 仿写 ButterKnifeLite
android·kotlin
灿飞1 天前
Kotlin与Java虚拟机十一:类与属性:构造顺序、backing field 与显式 backing field
java·后端·kotlin
传奇开心果1 天前
【探秘 Jetpack Compose 框架深水区】 第8课:rememberSaveable 的边界在哪里?——Bundle、Saver 与什么值得跨进程存活
android·kotlin
Kapaseker1 天前
领导问我 Kotlin 的 Nothing 是什么?
android·kotlin
传奇开心果编程2 天前
【Jetpack Compose娓娓道来】第36课:焦点管理与键盘输入——让遥控器、键盘和输入法都“找得到北”
android·kotlin·移动开发·交互·android jetpack·ui框架·声明式ui