Kotlin线程安全本机懒惰单身与参数

时间:2016-02-23 20:36:29

标签: multithreading singleton kotlin

在java中,我们可以使用双重Checked Locking& amp;编写thead-safe单例。易失性:

    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块中调用构造函数。基于此,我们可以认为它不是懒惰的。

Сlose到正确答案。

    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开发人员将来能够实现非反思......

3 个答案:

答案 0 :(得分:23)

Kotlin具有相当于您的Java代码,但更安全。即使是Java ,也不建议使用<{3}} 。在Java中,您应该使用double lock checkinner class on the static中也会对此进行解释。

但那是Java。 在Kotlin中,只需使用一个对象(一个可选的懒惰委托):

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中单身人士的困惑。并避免错误的版本&#34;这种模式 - 其中有很多。相反,它提供了更简单,最安全的单身形式。

考虑到使用lazy(),如果你有其他成员,每个人都会懒得。因为它们是在传递给lazy()的lambda中初始化的,所以你可以做一些关于自定义构造函数和每个成员属性的问题。

因此,您延迟加载Singletons对象(首次访问实例),然后加载something首次访问时成员),以及对象构建的完全灵活性。

另见:

作为附注,查看Kotlin的对象注册表类型库,它们与依赖注入类似,为您提供带注入选项的单例:

答案 1 :(得分:14)

Object declaration正是出于此目的:

object Singleton {
    //singleton members
}

它是懒惰且线程安全的,它在第一次调用时初始化,就像Java的静态初始化器一样。

您可以在顶级或类或其他对象内声明object

有关使用Java的object的更多信息,请参阅this answer

<小时/> 至于参数,如果你想要实现完全相同的语义(第一次调用getInstance采用其参数初始化单例,后面的调用只返回实例,删除参数),我建议这个结构:< p>

private object SingletonInit { //invisible outside the file
    lateinit var arg0: String
}

object Singleton {
    val arg0: String = SingletonInit.arg0
}

fun Singleton(arg0: String): Singleton { //mimic a constructor, if you want
    synchronized(SingletonInit) {
        SingletonInit.arg0 = arg0
        return Singleton
    }
}

此解决方案的主要缺陷是,它需要在单独的文件中定义单例以隐藏object SingletonInit,并且在初始化之前不能直接引用Singleton。 / p>

另外,请参阅a similar question有关为单身人士提供参数的信息。

答案 2 :(得分:4)

我最近写了an article on that topic。 TL; DR这是我提出的解决方案:

1)创建一个SingletonHolder类。你只需要写一次:

open class SingletonHolder<out T, in A>(creator: (A) -> T) {
    private var creator: ((A) -> T)? = creator
    @Volatile private var instance: T? = null

    fun getInstance(arg: A): T {
        val i = instance
        if (i != null) {
            return i
        }

        return synchronized(this) {
            val i2 = instance
            if (i2 != null) {
                i2
            } else {
                val created = creator!!(arg)
                instance = created
                creator = null
                created
            }
        }
    }
}

2)在你的单身人士中使用它:

class MySingleton private constructor(arg: ArgumentType) {
    init {
        // Init using argument
    }

    companion object : SingletonHolder<MySingleton, ArgumentType>(::MySingleton)
}

单例初始化将是惰性和线程安全的。