シングルトンパターンの基礎
シングルトンパターンは、Javaの設計パターンの中で最も基本的かつ頻出の一つです。このパターンは「生成型パターン」に分類され、特定のクラスから唯一のインスタンスしか生成できないように制約を加える仕組みです。
この設計は、アプリケーション全体で共有リソースを管理する必要がある場合に特に有効です。たとえば、データベース接続、設定ファイル、ログ出力など。
シングルトンを実現するための条件
- クラス自身が唯一のインスタンスを保持する
- 外部からのインスタンス生成を禁止する(プライベートコンストラクタ)
- 外部にインスタンスへのアクセス手段を提供する
主な実装方法
イーターモード(即時初期化)
アプリケーション起動時にインスタンスをすぐに生成する方式です。
class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
// コンストラクタはプライベート
}
public static Singleton getInstance() {
return INSTANCE;
}
}
- メリット: スレッドセーフ、同期処理不要
- デメリット: アプリケーション起動時に必ずメモリを消費
レイジーモード(遅延初期化)
初めてアクセスがあったときだけインスタンスを生成します。
シングルスレッド版(非スレッドセーフ)
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
マルチスレッド対応版
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- volatile修飾子でメモリ可視性を保証
- ダブルチェックロックにより、初期化後はロック不要
- メリット: 初期化の遅延でリソース節約
- デメリット: 実装が複雑、同期処理のオーバーヘッド
設計上の選択肢とトレードオフ
イーターモードはシンプルで高速ですが、初期化が早すぎるというデメリットがあります。
一方、レイジーモードは初期化のタイミングを遅らせられますが、スレッド安全性を確保するための工夫が必要です。
一般的には、以下のような判断基準が使われます:
- 初期化コストが低い → イーターモード
- 初期化コストが高い or 使わない可能性がある → レイジーモード