TechsMex

技術エンジニア C++/Python/Java

Bill Pugh singleton (initilization-on-demand holder idiom)

概要

Singletonの実装方法を探している際に見つけたエレガントで感動した書き方について紹介する。

一般的なSingletonの実装方法

下記に一般的な実装方法を紹介する。

public class GeneralSingleton {
    private static GeneralSingleton instance = new GeneralSingleton();

    private GeneralSingleton() {}

    private static GeneralSingleton getInstance() {
        return instance;
    }
}

もしくは遅延評価させるために下記の例もよく見られる。

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
    }

    private static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

Bill Pugh Singleton

Bill Pughは考案者の名前である。このSingletonは一言で言うとInitilization-on-demand holder idiomを適用させたSingletonらしい。

public class BillPughSingleton {
    private BillPughSingleton() {}

    public static BillPughSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        static final BillPughSingleton INSTANCE = new BillPughSingleton();
    }
}

このパターンの肝はJavaの仕様とInner classであるSingletonHolderにある。

JVMにBill Pugh Singletonがloadされた場合、一旦は初期化は無視される。

そして、SingletonHolderの中のINSTANCEは評価されるまで初期化されないため、呼び出された際に初めて初期化される。

この時、最初に呼び出したスレッドにおいてこの値は確定するため、自然にスレッドセーフになるという特徴を備えている。

ここら辺は正直完全に理解できていないため、後日追記する。

一般的なSingletonとの違い

先に二つのSingletonを紹介したが、下記のような欠点がある。

  • GeneralSingltonでは遅延初期化を行わないため、インスタンスが大きい場合JVM起動時に処理が遅くなる。

  • LazySingletonはスレッドセーフでない。スレッドセーフにするためにはsynchronized修飾子が必要だが、これはパフォーマンス低下を引き起こす場合がある。

Bill Pugh Singletonは上記の欠点をシンプルな書き方で解決が可能である。欠点としてはなぜスレッドセーフになるのか説明しづらい点だと思う。

参考