Javaでシングルトンパターンを安全かつ効率的に実装する方法はいくつか存在しますが、この記事では「ダブルチェックロッキング」と「初期化ホルダークラスイディオム」の二つのアプローチに焦点を当てます。
ダブルチェックロッキング
ダブルチェックロッキングは、シングルトンインスタンスが必要になるまでその生成を遅延させるテクニックです。以下にその実装例を示します。
public class Singleton {
// volatileキーワードで可視性を確保
private static volatile Singleton instance = null;
// privateコンストラクタで外部からのインスタンス生成を防ぐ
private Singleton() {}
// インスタンスを取得する唯一のpublicメソッド
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
ポジティブなポイント
- スレッドセーフ:複数のスレッドがインスタンスを同時に生成しようとしても、
synchronized
ブロックがこれを防ぎます。 - パフォーマンス:インスタンスが存在している場合、
synchronized
ブロックを回避し、パフォーマンスを向上させます。
改善の余地
- 初期化のオーバーヘッド:
synchronized
ブロックは比較的高コストな操作であるため、パフォーマンスが低下する可能性があります。
初期化ホルダークラスイディオム
Javaの初期化ホルダークラスイディオムは、クラスの自然な初期化プロセスを利用して、スレッドセーフなシングルトンを提供します。
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
この方法は、クラスが最初に参照された時に一度だけインスタンスを生成します。
この方法の利点
- シンプルさ:実装が簡潔で理解しやすい。
- パフォーマンス:
synchronized
は使用されず、インスタンスの生成はクラスが最初にロードされたときに一度だけ行われます。
総括
ダブルチェックロッキングは有効な手法ですが、初期化ホルダークラスイディオムの方が現代的なアプローチとして推奨されます。後者はより簡潔で、パフォーマンスの面でも優れています。