kotlin—lazy及其原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin—lazy及其原理相关的知识,希望对你有一定的参考价值。

参考技术A lazy是属性委托的一种,是有kotlin标准库实现。它是属性懒加载的一种实现方式,在对属性使用时才对属性进行初始化,并且支持对属性初始化的操作时进行加锁,使属性的初始化在多线程环境下线程安全。lazy默认是线程安全的。

lazy既然是属性委托的一种,那么其语法也遵循属性委托的语法:

对应的lazy 的语法为:

由于lazy为函数,其最后一个参数是函数,那么可以使用lamda的语法代替最后一个函数参数:

通过2中的语法,我们知道lazy是kotlin标准库中的重载函数,我们先从标准库lazy的函数的分析其原理:

lazy函数默认情况下是同步安全锁模式,其可以指定线程同步模式、线程公有模式、非线程安全模式,也在同步模式时指定使用的锁对象,lazy函数会创建懒加载类的实现类,通过懒加载类的实现类实现不同模式的懒加载。
我们依次分析SynchronizedLazyImpl、SafePublicationLazyImpl、UnsafeLazyImpl这三种模式是怎么实现懒加载的:

SynchronizedLazyImpl是同步模式的懒加载,它是lazy的默认实现,其在多线程环境下进行初始化是线程安全的,我们看看其源码实现:

同步模式的懒加载SynchronizedLazyImpl的实现原理其实是使用两个属性,一个是公有属性value—对外代表属性的值,一个是私有属性_value——是真正的值。value的get内部对_value进行初始化,如果_value已初始化则直接返回,如果没有初始化过则加锁并调用初始化函数把返回值赋值给_value。

SafePublicationLazyImpl是多线程环境下的公共线程安全模式,我们从其源码分析其原理:

公共线程安全模式SafePublicationLazyImpl与同步模式SynchronizedLazyImpl的区别在于,SafePublicationLazyImpl使用自旋锁进行初始化操作,而SynchronizedLazyImpl是要同步锁的方式进行初始化操作,其他与SynchronizedLazyImpl的实现一样。

SafePublicationLazyImpl是非线程安全的懒加载实现模式,在单线程下进行初始化是没啥问题,但是多线程下是进行初始化是不安全的,我们从其源码分析其原理:

SafePublicationLazyImpl与前面的两种模式的实现方式不一样就是初始化时没有加任何锁,其它是一样的。

上面分析了使用lazy函数之后返回了不同的懒加载实现类及各懒加载实现类的原理,所以lazy的语句最终语句的是:
val propertyName by [SynchronizedLazyImpl | SafePublicationLazyImpl | UnsafeLazyImpl]
但具体是怎么个懒加载实现类的value的get方法呢?——下面我们举例,然后通过编译后的字节码分析器实现原理:
举例:

编译后的字节码文件:

通过对生成的字节码的分析,lazy的原理:

注意lazy实现了懒加载,达到在使用时才进行初始化的目的,但是也为此增加了一个懒加载类,如果一个类的初始化操作不耗时却使用lazy进行懒加载是不明智的,lazy的适合场景是类的初始化操作比较耗时占资源。

Kotlin 中的 by lazy与lateinit

lateinit 只用于变量 var

而 lazy 只用于常量 val

lateinit 应用于初始化第一次为空。但是调用前必须有赋值 否则报错。

lazy 应用于单例模式(if-null-then-init-else-return),而且当且仅当变量被第一次调用的时候,委托方法才会执行。

以上是关于kotlin—lazy及其原理的主要内容,如果未能解决你的问题,请参考以下文章

能说一说 Kotlin 中 lateinit 和 lazy 的区别吗?

面试官:能说一说 Kotlin 中 lateinit 和 lazy 的区别吗

Kotlin Vocabulary | Kotlin 内建代理

面试官:能说一说 Kotlin 中 lateinit 和 lazy 的区别吗?

Kotlin Vocabulary | Kotlin 内建代理

kotlin 的 JPA:lazy 和 @Transient 不适用于休眠