在 java 中,我们可以使用双重检查锁定和 volatile 编写安全的单例:
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance(String arg) {
Singleton localInstance = instance;
if (localInstance == null) {
synchronized (Singleton.class) {
localInstance = instance;
if (localInstance == null) {
instance = localInstance = new Singleton(arg);
}
}
}
return localInstance;
}
}
我们如何在 kotlin 中编写它?
关于对象
object A {
object B {}
object C {}
init {
C.hashCode()
}
}
我使用 kotlin 反编译器来得到它
public final class A {
public static final A INSTANCE;
private A() {
INSTANCE = (A)this;
A.C.INSTANCE.hashCode();
}
static {
new A();
}
public static final class B {
public static final A.B INSTANCE;
private B() {
INSTANCE = (A.B)this;
}
static {
new A.B();
}
}
public static final class C {
public static final A.C INSTANCE;
private C() {
INSTANCE = (A.C)this;
}
static {
new A.C();
}
}
}
所有对象在 static
block 中都有构造函数调用。基于它,我们可以认为它并不偷懒。
С失去正确答案。
class Singleton {
companion object {
val instance: Singleton by lazy(LazyThreadSafetyMode.PUBLICATION) { Singleton() }
}
}
反编译:
public static final class Companion {
// $FF: synthetic field
private static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Singleton.Companion.class), "instance", "getInstance()Lru/example/project/tech/Singleton;"))};
@NotNull
public final Singleton getInstance() {
Lazy var1 = Singleton.instance$delegate;
KProperty var3 = $$delegatedProperties[0];
return (Singleton)var1.getValue();
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
我希望 Kotlin 开发者在未来做出非反射实现...
最佳答案
Kotlin 与您的 Java 代码等效,但更安全。您的 double lock check不推荐即使是Java。在 Java 中,您应该使用 inner class on the static Initialization-on-demand holder idiom 中也对此进行了解释.
但那是 Java。 在 Kotlin 中,只需使用一个对象(以及可选的惰性委托(delegate)):
object Singletons {
val something: OfMyType by lazy() { ... }
val somethingLazyButLessSo: OtherType = OtherType()
val moreLazies: FancyType by lazy() { ... }
}
然后您可以访问任何成员变量:
// Singletons is lazy instantiated now, then something is lazy instantiated after.
val thing = Singletons.something // This is Doubly Lazy!
// this one is already loaded due to previous line
val eager = Singletons.somethingLazyButLessSo
// and Singletons.moreLazies isn't loaded yet until first access...
Kotlin 有意避免人们对 Java 中的单例感到困惑。并避免这种模式的“错误版本”——其中有很多。相反,它提供了更简单和最安全的单例形式。
考虑到 lazy()
的使用,如果您有其他成员,每个成员都会单独变得懒惰。由于它们是在传递给 lazy()
的 lambda 中初始化的,因此您可以执行您所要求的有关自定义构造函数和每个成员属性的事情。
因此,您会延迟加载 Singletons
对象(在第一次访问实例时),然后延迟加载 something
(< em>第一次访问成员时),以及对象构造的完全灵 active 。
另见:
附带说明,查看类似于依赖注入(inject)的 Kotlin 对象注册表类型库,为您提供带有注入(inject)选项的单例:
关于multithreading - 带参数的 Kotlin 线程安全 native 惰性单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35587652/