0

アイデアは、「タイプ」に基づいて異なるシングルトン インスタンスを返すファクトリ クラスを作成することです。【マルチトンパターン】。また、シングルトン インスタンスは遅延して作成する必要があります。

以下のコードはスレッドセーフですか? ConcurrentHashMap を使用すると簡単になりますが、HashMap で試してみたいと思います。

public class Multiton {

    private HashMap<String, Interface> interfaceMap;

    private static class Holder {
        public static final Multiton INSTANCE = new Multiton();
    }

    public static Multiton getInstance() {
        return Holder.INSTANCE;
    }

    private Multiton(){
        interfaceMap = new HashMap<String, Interface>();        
    }

    public Interface getInterface(String key){
        Interface value = interfaceMap.get(key);
        if(null == value){
            synchronized(interfaceMap){
                // double check locking
                if(interfaceMap.get(key) == null){
                    switch(key){
                    case TypeA : // initialize Type A interface here and put it to map
                        value = new TypeA();
                        interfaceMap.put(key, value);
                        break;
                    case TypeB : // initialize Type B interface here and put it to map
                        value = new TypeB();
                        interfaceMap.put(key, value);
                        break;
                    }
                }
            }
        }
        return interfaceMap.get(key);
    }
}
4

1 に答える 1

0

二重チェック ロックは (一般に) スレッド セーフではありません。特に、マップへの書き込み時に同期するだけでは十分ではありません。これは、ライター スレッドが現在変更している状態にリーダー スレッドがアクセスすることを妨げないためです。

ConcurrentHashMap を使用できない場合 (たとえば、単一の TypeA がすべてのクライアントで使用されるだけでなく、単一の TypeA が作成されるようにする必要があるため)、次の方法が機能し、合理的に安価になります。特に、遅延オブジェクトが構築されると、ロックフリーになります。

abstract class Lazy<T> {
    private volatile T instance;

    abstract T create();

    void get() {
        if (instance == null) {
            synchronized (this) {
                if (instance == null) {
                    instance = create();
                }
            }
        }
        return instance;
    }
}

class Multiton {
    private final Map<String, Lazy<?>> map = new HashMap<>();

    Multiton() {
        map.put("A", new Lazy<A> {
            A create() {
                return new A();
            }
        }
        map.put("B", new Lazy<B> {
            B create() {
                return new B();
            }
        }
        // and so on for the other types
    }
}

製品品質のために、ファクトリ メソッドに lamdba 式を使用し、マップ (要求されたインターフェイスのクラス オブジェクトなど) に安全なキーを入力することを検討することをお勧めします。

于 2014-08-27T22:29:40.473 に答える