Singleton パターンの問題点を解決する

Advertisement

問題

要求されたオブジェクトを返すメソッド getInstance() 内でインスタンスを生成する場合のコードを書いてみる。
import java.util.*;

final class Single{
    private static Vector list = null;

    private Single(){} // インスタンス化禁止

    // オブジェクトを利用するときはこのメソッドを使用。
    public static Vector getInstance(){

        // 生成されていなければ生成する。
        if(list == null){
            list = new Vector();
        }

        return list;
    }
}
上記のコードの場合、getInstance() が複数のクライアントから同時に呼び出され、最初の処理が ifブロックに入り、new Vector() が実行される前に、後続の処理がifブロックに入った場合、new Vector() が2回実行されることになり、Singleton オブジェクトが複数生成されることになる。

これを避けるために同期化を使用してプログラムを修正する。
import java.util.*;

final class Single{
    private static Vector list = null;

    private Single(){} // インスタンス化禁止

    // オブジェクトを利用するときはこのメソッドを使用。
    synchronized public static Vector gerInstance(){

        // 生成されていなければ生成する。
        if(list == null){
            list = new Vector();
        }

        return list;
    }
}
これで getInstance() メソッドが複数のクライアントから同時に呼ばれても、排他状態で実行されるようになるため、オブジェクトが複数生成されることはなくなる。
ただし Singleton という制約を満たすことはできたが、この getInstance() メソッドが頻繁に呼ばれるメソッドの場合、待ち状態が多発することになり、パフォーマンスに著しい影響を及ぼすことになる。

これを解決するのがダブルチェックという方法である。ダブルチェックを使用してコードを修正してみる。
(注意)ダブルチェックはJVMの実装によって、正しく動作しない場合があります。
import java.util.*;

final class Single{
    private static Vector list = null;

    private Single(){} // インスタンス化禁止

    // オブジェクトを利用するときはこのメソッドを使用。
    public static Vector gerInstance(){

        // 生成されていなければ生成する。
        if(list == null){
            synchronized(list){
                if(list == null){
                    list = new Vector();
                }
            }
        }

        return list;
    }
}
これで2重にインスタンスが生成される問題が解決され、さらに一度インスタンスが生成されれば2度と synchronized ブロックには到達しないため、パフォーマンスに影響を及ぼすこともなくなる。

Advertisement

ショートカット

634トップページ
このカテゴリのトップページに戻る
634ラボ

サイト検索

Google

Web サイト内

Y!ログール