一 饿汉模式
/**
* 饿汉模式
*/
object SingleTest {
fun show() {
println("饿汉模式")
}
}
object修饰的类,既是单例的实例,又是类名,又是对象 Kotlin中的object就声明了一个类为饿汉模式的单例,经过object修饰过得类就是一个静态类,默认实现了饿汉模式
饿汉模式优点:方便,快,一个object关键字就OK了,线程安全的 饿汉模式缺点:类加载慢,不能延时加载,浪费内存
二 懒汉模式
这个是懒汉模式模式的2种写法 左边的用了!!我是不喜欢用断言,会有风险,喜欢用右边的更优雅
/**
* 懒汉模式
*/
class SingleTest1 {
companion object {
private val singleTest by lazy { SingleTest1() }
fun getInstance() = singleTest
}
fun show() {
println("懒汉模式")
}
}
线程不安全, 懒汉模式的KT版本代码也很少,用到了半身对象和by lazy 延迟创建对象
Kotlin推荐采用companion object来声明一个静态变量或者静态方法,等同于Java的static。依赖 JVM 的类加载机制确保唯一和线程安全; JVM 加载类采用「按需加载」策略。
三 双重检测模式
/**
* 双重检测模式
*/
class SingleTest2 {
companion object {
private val singleTest by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingleTest2() }
fun getInstance() = singleTest
}
fun show() {
println("双重检测模式")
}
}
这种是Kotlin推荐的通过by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED)来创建一个双重检测的单例模式,和懒汉模式(线程不安全),只是mode不一样。
我来看看lazy内部源码
//expect关键字标记这个函数是平台相关,我们需要找到对应的actual关键字实现表示平台中一个相关实现
public expect fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T>
//对应多平台中一个平台相关实现lazy函数
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
//根据不同mode,返回不同的Lazy的实现,我们重点看下SynchronizedLazyImpl
LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
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//为了解决DCL带来指令重排序导致主存和工作内存数据不一致的问题,这里使用Volatile原语注解。具体Volatile为什么能解决这样的问题请接着看后面的分析
private val lock = lock ?: this
override val value: T
get() {
//当外部调用value值,get访问器会被调用
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
//进行第一层的Check, 如果这个值已经初始化过了,直接返回_v1,避免走下面synchronized获取同步锁带来不必要资源开销。
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
//进行第二层的Check,主要是为了_v2被初始化直接返回
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
//如果没有初始化执行initializer!!() lambda,
//实际上相当于执行外部调用传入的 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { KLazilyDCLSingleton() } 中的KLazilyDCLSingleton()也即是返回KLazilyDCLSingleton实例对象
val typedValue initializer!!()
_value = typedValue//并把这个实例对象保存在_value中
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)
}
Lazy是接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
还有 静态内部类式(线程安全,调用效率高,可以延时加载)和枚举等单例模式 ,枚举单例我是用的很少,大家做个了解。
|