多线程模式下的单例创建

16 阅读2分钟

Java 单例 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;  
    }  
} 
  1. 使用枚举的方式 其实这种方式和上面的方式基本相同,枚举类在编译后其实也是把内部的每个枚举形成对应的静态实例,相比第一种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();
}
  1. 使用静态内部类的方式,这种方式也可以实现懒加载(在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<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, 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)
}