Это ошибка в Котлине или я чего-то не хватает?

Мне не нужно много опыта в многопоточности. Поэтому не уверен, что я получил право на следующий код Java, декомпилированный из Kotlin.

Вот код Котлина:

companion object {
    @Volatile private var INSTANCE: SomeDatabase? = null

    fun getInstance(context: Context): SomeDatabase =
            INSTANCE ?: synchronized(this) {
                INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
            }
}

Вот декомпилированный код в Java:

     SomeDatabase var10000 = ((SomeDatabase.Companion)this).getINSTANCE();
     if (var10000 == null) {
        synchronized(this){}

        SomeDatabase var4;
        try {
           var10000 = SomeDatabase.Companion.getINSTANCE();
           if (var10000 == null) {

               ...

        var10000 = var4;
     }

     return var10000;

Разве это не означает, что код фактически не синхронизирован из-за пустого блока в synchronized(this){}?

Ответы

Ответ 1

Если вы посмотрите на сам байт-код без его декомпиляции, вы увидите, что синхронизация происходит так, как должна - это версия, лишенная множества операций загрузки и хранения, номеров строк и т.д., Но важно то, где MONITORENTER и инструкции MONITOREXIT:

public final getInstance(Landroid/content/Context;)Lcom/example/SomeDatabase;
    LDC "context"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
    INVOKESTATIC com/example/Foo.access$getINSTANCE$cp ()Lcom/example/SomeDatabase;
    MONITORENTER
    INVOKESTATIC com/example/Foo.access$getINSTANCE$cp ()Lcom/example/SomeDatabase;
    INVOKESTATIC com/example/FooKt.buildDatabase (Landroid/content/Context;)Lcom/example/SomeDatabase;
    INVOKESTATIC com/example/Foo.access$setINSTANCE$cp (Lcom/example/SomeDatabase;)V
    MONITOREXIT
    MONITOREXIT
    ARETURN

Проблема, которую вы видите, не является ошибкой в компиляторе, а скорее проблемой с декомпилятором, что не особенно редок. Это довольно сложная задача - декомпилировать произвольный сгенерированный байт-код обратно на Java.