pun*_*sta 19 singleton multithreading kotlin
在java中,我们可以使用双重Checked Locking&volatile编写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;
}
}
Run Code Online (Sandbox Code Playgroud)
我们怎么能用kotlin写呢?
object A {
object B {}
object C {}
init {
C.hashCode()
}
}
Run Code Online (Sandbox Code Playgroud)
我使用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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
所有对象都在static块中调用构造函数.基于此,我们可以认为它不是懒惰的.
class Singleton {
companion object {
val instance: Singleton by lazy(LazyThreadSafetyMode.PUBLICATION) { Singleton() }
}
}
Run Code Online (Sandbox Code Playgroud)
反编译:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我希望Kotlin开发人员将来能够实现非反思......
Jay*_*ard 24
Kotlin具有相当于您的Java代码,但更安全.你的双重锁定检查不建议甚至对Java.在Java中,您应该在static上使用内部类,这也在Initialization-on-demand holder惯用法中进行了解释.
但那是Java. 在Kotlin中,只需使用一个对象(一个可选的惰性委托):
object Singletons {
val something: OfMyType by lazy() { ... }
val somethingLazyButLessSo: OtherType = OtherType()
val moreLazies: FancyType by lazy() { ... }
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以访问任何成员变量:
// 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...
Run Code Online (Sandbox Code Playgroud)
Kotlin有意避免人们对Java中单身人士的困惑.并避免这种模式的"错误版本" - 其中有许多.相反,它提供了更简单,最安全的单身形式.
鉴于使用lazy(),如果你有其他成员,每个人都会懒得.因为它们是在传递给lazy()你的lambda中初始化的,所以你可以做一些关于自定义构造函数和每个成员属性的问题.
因此,您可以延迟加载Singletons对象(在第一次访问实例时),然后进行更长时间的加载something(在成员的第一次访问时),以及对象构造的完全灵活性.
也可以看看:
作为旁注,请查看Kotlin的对象注册表类型库,它们与依赖注入类似,为您提供带注入选项的单例:
hot*_*key 14
对象声明正是为此目的:
object Singleton {
//singleton members
}
Run Code Online (Sandbox Code Playgroud)
它是惰性和线程安全的,它在第一次调用时初始化,就像Java的静态初始化器一样.
您可以object在顶级或类或其他对象内声明.
有关使用objectJava 处理s的更多信息,请参阅此答案.
getInstance使其参数初始化单例,后面的调用只返回实例,删除参数),我会建议这个结构:
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
}
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案的主要缺陷是它需要在单独的文件中定义单例以隐藏它object SingletonInit,并且在Singleton初始化之前不能直接引用.
另外,请参阅有关向单例提供参数的类似问题.
我最近写了一篇关于该主题的文章。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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
2)在您的单例中使用它:
class MySingleton private constructor(arg: ArgumentType) {
init {
// Init using argument
}
companion object : SingletonHolder<MySingleton, ArgumentType>(::MySingleton)
}
Run Code Online (Sandbox Code Playgroud)
单例初始化将是惰性的并且是线程安全的。