只介绍懒汉模式,并且线程安全的写法
Java版本
1、双重检查,加锁
public class Singleton {
// --- 双层锁定 线程安全
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
分析:当同时有两个线程访问getInstance()
时,synchronized 前的instance == null
两个线程都会通过,当执行synchronized (Singleton.class)
时候会有一个线程进入,另一个线程等待的情况,进入的线程会再次对instance == null
进行判断并创建一个Singleton的实例,然后结束synchronized 代码块。另一个等待线程进入synchronized 代码块,在进行instance == null
判断时会发现instance 已经不再为null,从而不再创建Singleton的实例,这样就可以确保Singleton对象在多线程情况下也只有一个实例。那你会不会问在synchronized 前的instance == null
又有什么作用呢?这个主要是考虑效率的问题,如果不在synchronized 前加上instance == null
,就会发现每次调用都会对线程加锁,消耗资源又达不到高效性。
2、静态内部类,写法简单优雅
public class Singleton {
// --- 静态内部类 线程安全
private Singleton() {}
public static Singleton getInstance() {
return Holder.instance;
}
private static class Holder {
private static Singleton instance = new Singleton();
}
}
分析:其实这是一种偷懒的线程安全实现方法,为什么说是偷懒那?那是因为这种实现利用了类的加载是线程安全的原理。当这个Singleton 被加载的时候,其中的内部类Holder 并不会被加载,只有当调用getInstance()
中的Holder.instance
时Holder 才会被加载,而类的加载一定是线程安全,至于为什么类的加载是线程安全的请 自行百度
Kotlin版本
1、双重检查,加锁
class Singleton private constructor() : IImageLoader {
companion object {
@Volatile
private var INSTANCE: Singleton ? = null
fun instance(): Singleton {
INSTANCE ?: synchronized(Singleton @ this) {
if (INSTANCE == null)
INSTANCE = Singleton (loader)
}
return INSTANCE!!
}
}
}
或者
class SingletonK private constructor() {
companion object {
val Instanc: SingletonK by lazy { SingletonK() }
}
}
分析:为什么val Instanc: SingletonK by lazy { SingletonK() }
这样就可以实现线程安全?这要看lazy的实现源码lazy其实是可以有参数的,它的参数类型是LazyThreadSafetyMode
,当我们不传的时候默认是LazyThreadSafetyMode.SYNCHRONIZED
也就是线程安全,那么我们再看看这种情况下的具体实现!
@kotlin.jvm.JvmVersion
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
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
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
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)
}
当我们看到get中的下面代码
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
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
}
}
这就不用我多说了,底层实现还是一个双重检查加锁的实现!!!