『大話設計モード』読書ノート:単例モードとJava同期ロックsynchronized


クラスにインスタンスが1つしかないことを保証し、グローバル・アクセス・ポイントを提供するシングル・インスタンス・モード.単一のインスタンス・モードでは、クラス自体が一意のインスタンスを保存します.このクラスは、他のインスタンスが作成されないことを保証し、インスタンスにアクセスする方法を提供する必要があります.単例モードのクラスでは,構造方法(関数/体)をprivateとして設定し,外部インスタンス化の可能性を塞いだ.同時に、クラスに静的メソッドを提供してクラスの一意のインスタンスを提供し、インスタンスが存在しない場合に初期化しようとします.
 
次の例では、単一のモードの典型的な実装を示します.
public class Singleton {
    private static Singleton instance;
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        if (instance == null) {
            instance = new Singleton();
        }
       
        return instance;
    }
}

 
上記の例では、単一のクラスのインスタンスは、最初に参照されたときに初期化され、このタイプの単一のクラスは「怠け者式」と呼ばれます.単例モードには2つのタイプがあり、もう1つは「餓漢式」と呼ばれ、単例クラスのインスタンスがロード時に初期化されることを意味し、以下に示す.
public class Singleton {
    private static Singleton instance = new Singleton();
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        return instance;
    }
}

 
単一のモードは、UIインタフェースのツールバー、Androidアプリケーションの警告ボックスなど、クラスが必要で、一度だけ初期化する必要がある場合に主に使用されます.単一スレッドプログラムでは,上記の2つの方式で生成された単一クラスが要求を満たすことができる.しかし、マルチスレッド環境では、複数のスレッドが怠け者の単一クラスを同時にインスタンス化すると、単一クラス内でインスタンスを複数回初期化し、単一モードが失効する可能性があります.したがって,マルチスレッドプログラムにおける怠け者式の一例については,スレッドの安全を確保するためにロックをかける必要がある.
 
Javaの同期ロックキーsynchronizedについては、次のリンクを参照してください.
http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html
 
簡単に言えばsynchronizedキーワードの使い方は、主に2つに分けられます.
1つは、メソッド定義時にメソッド名の前に付けられる、synchronized methodName(params){...};
2つ目は、synchronized(this){...}のような同期ブロックを宣言することです.
その役割は,修飾の方法やコードブロックに同期ロックを加えることである.1つのスレッドがこの方法またはコードブロックに実行されると、その部分はロックされ、その後の他のコードに実行されるスレッドは、前のスレッドが実行されるまでブロックされ、同期ロックが解放される.
 
次のコードは、スレッドが安全な怠け者のクラスの実装です.
public class Singleton {
    private static Singleton instance;
    private final static Object syncLock = new Object();
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        if (instance == null) {
            synchronized (syncLock) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
       
        return instance;
    }
}

 
synchronized同期ブロックの括弧内のロックオブジェクトは、関係のないObjectクラスインスタンスを採用していることに注意してください.通常synchronizedではなくロックとして使用されるthisは、getInstanceメソッドが静的メソッドであり、内部では静的またはインスタンス化されていないクラスオブジェクトを使用できないため(空のポインタ異常を回避します).また、ロックの対象としてinstanceを直接使用していないのは、ロック時にinstanceがインスタンス化されていない可能性があるためです(同様に空のポインタの異常を避けるためです).
また、getInstanceメソッドをsynchronizedメソッドに変更することは、一度そうすると、「大話設計モード」の21.5節の例と同じ効果になるため、単一のクラスでは推奨されません.この方法では、getInstanceメソッドを呼び出すたびにロックが必要になり、前例に比べて効率が低下します.