Doule Check 方式
/**
* double check
* 如果没有 synchronized 和 二次 checkNull 在单线程中没有任何问题。
* synchronized 保证只能有一个线程进入方法体中,其他的线程会进入等待队列。
* [_instance = new JavaTest()] 流程为: new 写入缓存 -> 更新到主存中,
*
* 为了防止中间过程被打断需要为变量添加 volatile
*
* volatile 可以保证数据的可见行,即数据直接会更新更新到主存中,其他线程都可以看到。
* 避免出现当前线程只是更新了缓存中的数据,而没有更新到主存中,在单例中就会导致其他线程再次创建实例,
* 这样就违反了单例的本质。
*/
private static volatile JavaTest _instance;
public static JavaTest getInstance() {
if (_instance == null) {
synchronized (JavaTest.class) {
if (_instance == null) {
_instance = new JavaTest();
}
}
}
return _instance;
}
2. 根据classload原理直接创建静态实例
public class Singleton {
private static Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
- 使用枚举的方式
其实这种方式和上面的方式基本相同,枚举类在编译后其实也是把内部的每个枚举形成对应的静态实例,相比第一种double-check方式缺少了lazy load
static enum SingletonEnum {
INSTANCE;
private JavaTest javaTest;
private SingletonEnum() {
javaTest = new JavaTest();
}
public JavaTest getInstance() {
return javaTest;
}
}
public static JavaTest getInstance2() {
return SingletonEnum.INSTANCE.getInstance();
}
- 使用静态内部类的方式,这种方式也可以实现懒加载(在Dagger和Hilt使用Singleton注入的类就是使用这种方式进行单例的实现的)
-
public class Singleton {
// 静态内部类
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
kotlin 单例
companion object {
val instance: KotlinTest by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
kotlinTest()
}
}
lazy 可以实现懒加载
LazyThreadSafetyMode.SYNCHRONIZED 对应下面的方法:
private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable {
private var initializer: (() -> T)? = initializer
// 这里同样适用了Volatile 来保持可见性
@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)
}