Kotlin スレッドセーフなネイティブ遅延シングルトン (パラメータ付き) 質問する

Kotlin スレッドセーフなネイティブ遅延シングルトン (パラメータ付き) 質問する

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ブロック内でコンストラクタを呼び出します。これに基づいて、これは遅延ではないと考えることができます。

正解に近いです。

    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 開発者が非リフレクション実装を行うことを期待しています...

ベストアンサー1

KotlinにはJavaコードと同等のコードがありますが、より安全です。ダブルロックチェック推奨されませんJavaでもJavaでは、静的な内部クラスこれはまた、オンデマンド初期化ホルダーイディオム

しかし、それは 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 のシングルトンに関する人々の混乱を意図的に回避します。また、このパターンの「間違ったバージョン」 (多数存在します) を回避します。代わりに、よりシンプルで安全な形式のシングルトンを提供します。

の使用を考えるとlazy()、他のメンバーがある場合、それぞれが個別に遅延されます。また、それらは に渡されるラムダで初期化されるため、lazy()コンストラクターのカスタマイズについて、および各メンバー プロパティについて質問していたことを行うことができます。

その結果、Singletonsオブジェクトの遅延読み込みが発生します(インスタンスへの最初のアクセス時)、そしてsomethingメンバーの初回アクセス時)、およびオブジェクト構築における完全な柔軟性を備えています。

参照:

ちなみに、依存性注入に似た、注入オプションを備えたシングルトンを提供する Kotlin のオブジェクト レジストリ タイプ ライブラリを調べてください。

おすすめ記事