オブジェクト指向設計


Singleton パターン - シングルトンパターン

2008/06/10 23:08Update
TAGS: Singleton | GoF | デザインパターン | OOD | オブジェクト指向設計

Singleton パターンはGoFによる23種類のデザインパターンの一つで、インスタンスの生成方法を提供します。Singleton パターンでは、クラスのインスタンスを一つしか生成しないことを保障できます。

はじめに


Singleton パターンはインスタンスの生成に関連するデザインパターンで、次のような機能や特徴を提供します:
◇ アプリケーション実行中に一つのみのインスタンスを生成する
◇ そのインスタンスを取得するためのstaticメソッド(インタフェース)を提供する
<<クラス図>>


Singleton パターンの使用シーン


◇ マルチスレッド環境で、リソースやオブジェクトなどが複数のスレッドから同時に利用されても正常に動作する必要がある
◇ グローバル変数やリソースの共有
◇ パフォーマンスのため、インスタンスの生成するのに生成時間をかかりたくない

Singleton パターンの実装方法


Singleton パターンのJAVA言語による典型的な実装にはいくつかの方法があります。C++などほかの言語も基本的には同じような考え方になります。

方法1:
//1)キーワードfinalで、継承不可に
public final class Singleton {
    //2)Singletonインスタンス(static final):instanceを定義
    private static final Singleton instance = new Singleton();
    //3)privateのコンストラクター。外部クラスのnewによるインスタンスの生成不可に
    private Singleton(){};
    //4)static メソッドで生成されたメソッドを取得
    public static Singleton getInstance(){
        return Singleton.instance;
    }

    //その他メソッド
    ...
}

上の1)、2)、3)、4)はSingletonパターンの実装の肝心的な部分です。
上記方法では、クラスフィールドを用いてinstanceを生成しています。
    //2)Singletonインスタンス(static final):instanceを定義
    private static final Singleton instance = new Singleton();

これはスレッドセーフではないので、最初の呼出は注意する必要があります(複数のスレッドから同時に呼ばされないように)。


方法2:
public final class Singleton {
    private static Singleton instance;
    private Singleton(){};
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

方法1と違って、instanceの生成はクラスフィールドではなく、getInstanceメソッドの中で生成されます。
また、synchronizedなので、getInstanceメソッドはスレッドセーフです、複数のスレッドどこから呼ばれても問題がありません。
しかし、同時に一つのスレッドからgetInstanceメソッドをしかアクセスできないので、パフォーマンス低下する恐れがあります。

方法3:
public final class Singleton {
    private static Singleton instance;
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (this) {
                //double-check
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

これはいわゆるDouble-Checked Lockingです、完璧な解決策だと見えますが、残念ながら、動作しないことと証明されています。
※参考資料部分をご参照ください


方法4:
public final class Singleton {
    private volatile static Singleton instance;
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (this) {
                //double-check
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

これはSingleton instanceにvolatileで修飾させることで、double-check volatileとも言われます。しかし、この方法は環境(コンパイラ)に依存しますので、動作しない可能性があります。

参考資料


The "Double-Checked Locking is Broken" Declaration 
C++ in Theory: Why the Double Check Lock Pattern Isn`t 100% Thread Safe 
double-checked lockingとSingletonパターン 「ibm.com@developerworks」

有关作者
Syboos.jp編集長AJavaやオープンソース情報の執筆、Webサイトの開発や運営全般の業務に携わる。

Sponsored Link


Comments