I'm trying to convert some part of my project from java
to kotlin
. One of it is a singleton manager class. The java class looks like this
public class Manager {
private static volatile Manager Instance = null;
private static final Object InstanceLock = new Object();
private Manager(Object1 object1, Object2 object2, Object3 object3){//...};
public static boolean isInitialized(){
synchronized(InstanceLock){
return Instance == null;
}
}
public static void initialize(Object1 object1, Object2 object2, Object3 object3){
if(Instance == null){
synchronized(InstanceLock){
if(Instance == null){Instance = new Manager(object1, object2, object3};
}
}
}
public static getInstance(){
Precondition.checkNotNull(Instance, msg...);
return Instance;
}
}
Also, I decompiled .kt back to java. In the companion class I get the following code.
public static final class Companion {
@Nullable
public final Manager getInstance() {
return Manager.instance;
}
private final void setInstance(Manager var1) {
Manager.instance = var1;
}
private final Object getInstanceLock() {
return Manager.InstanceLock;
}
public final boolean isInitialized() {
Object var1 = Manager.Companion.getInstanceLock();
synchronized(var1){}
boolean var4;
try {
var4 = Manager.Companion.getInstance() == null;
} finally {
;
}
return var4;
}
public final void initialize(@NotNull String string1, @NotNull String string2) {
Intrinsics.checkParameterIsNotNull(string1, "string1");
Intrinsics.checkParameterIsNotNull(string2, "string2");
if (((Manager.Companion)this).getInstance() == null) {
Object var3 = ((Manager.Companion)this).getInstanceLock();
synchronized(var3){}
try {
if (Manager.Companion.getInstance() == null) {
Manager.Companion.setInstance(new Manager(string1, string2, (DefaultConstructorMarker)null));
}
Unit var5 = Unit.INSTANCE;
} finally {
;
}
}
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
1) How do I achieve thread safety, singleton by using lateinit or lazy inside the kotlin companion object ? As I can see, the decompiled java code has a synchronized call in initialize function but nothing in the synchronize body.
2) I think kotlin object/lazy comes with thread safety guarantee, how do I take advantage of it in the double-checked locking pattern ?
3) Is there a better pattern than double-checked locking pattern? Assuming the constructor does need arguments.
4) Since I'm trying to make the impact of converting this manager class to kotlin file as small as possible (this Manager file is supposed to work with the rest of java code), what is the best approach ? I do notice I have to add @Jvmstatic
or @Jvmfield
in some other variables or functions inside of companion object so that I don't have to update other java file that has call to these static field in manager.
5) Additional question, what if this manager is now working in pure kotlin environment, what's the best practice of implementing a singleton class with multiple arguments ?