0

synchronizationJava ディレクティブを使用して、クラスにきめ細かい同期を実装しようとしています。つまり、同期できるコードの量を最小限に抑えようとしています。コードをインラインでコメントして、何をするかを説明し、コードの後に​​コメントします。コードを改善する方法を尋ねます。

public class MyClass {
    private static volatile MyClass singletonInstance = null;

    private HashMap<String, Integer> mHashMap = null;
    private String mStringA = null;
    private String mStringB = null;


     // Use double check technique to use synchronization only 
     // at the first getInstance() invocation
    public static MyClass getInstance() {
        if (singletonInstance == null) {
            synchronized (MyClass.class) {
                if (singletonInstance == null)
                    singletonInstance = new MyClass();
                    // Initialize class member variables
                    singletonInstance.mHashMap = new HashMap<String,Integer>();
                    singletonInstance.mStringA = new String();
                    singletonInstance.mStringB = new String();
            }

        }
        return singletonInstance;
    }

    // The following two methods manipulate the HashMap mHashMap
    // in a secure way since they lock the mHashMap instance which
    // is always the same and is unique
    public Integer getIntegerFromHashmap(String key) {
        synchronized (mHashMap) {
            return mHashMap.get(key);
        }
    }

    public void setIntegerIntoHashmap(String key, Integer value) {
        synchronized (mHashMap) {
            mHashMap.put(key, value);
        }
    }

    // With the two String members mStringA and mStringB the problem is 
    // that the instance of String pointed by the member is varied by the 
    // setter methods, so we can not lock in a fine grained way and we
    // must lock on the singletonInstance.
    public String getStringA() {
        synchronized (singletonInstance) {
            return mStringA;
        }
    }

    public String getStringB() {
        synchronized (singletonInstance) {
            return mStringB;
        }
    }

    public void setStringA(String newString) {
        synchronized (singletonInstance) {
            mStringA = newString;
        }
    }

    public void setStringB(String newString) {
        synchronized (singletonInstance) {
            mStringB = newString;
        }
    }
}

String2 つのメンバー変数の getter メソッドと setter メソッドについて私が気に入らない点は、ロックをオンにsingletonInstanceすると、アクセスしようとしているスレッドが、操作中のスレッドがそのロックを解放するmStringBまで待機する可能性があることです。mStringAこの場合、あなたはどうしますか?private final Integer mStringALock = new Integer(0) とprivate final Integer mStringBLock = new Integer(0)inのような 2 つのメンバー変数を作成し、それぞれとMyClassのゲッター メソッドとセッター メソッドの同期ブロックで使用しますか?mStringAmStringB

String上記のコードとメンバー変数のきめの細かい同期のために提案されたバリエーションを改善する方法についていくつかのアイデアがある場合は、大歓迎です:)

4

3 に答える 3

3

多くの場合、単純なソリューションは実装が容易です。2004 年に追加された並行ライブラリも使用します。

これには明示的なロックは必要なく、各コンテナーはスレッド セーフです。

AtomicReference を使用できますが、この場合、 volatile がまだ提供していないものは何も提供しません。(kdgregory が指摘したように) より複雑なケースでは AtomicReference を使用できます。

public enum MyClass {
    INSTANCE;

    private final Map<String, Integer> mHashMap = new ConcurrentHashMap<String, Integer>();
    private volatile String mStringA = null;
    private volatile String mStringB = null;


    // The following two methods manipulate the HashMap mHashMap
    // in a secure way
    public Integer getIntegerFromHashmap(String key) {
        return mHashMap.get(key);
    }

    public void setIntegerIntoHashmap(String key, Integer value) {
        mHashMap.put(key, value);
    }

    public String getStringA() {
        return mStringA;
    }

    public String getStringB() {
        return mStringB;
    }

    public void setStringA(String newString) {
        mStringA = newString;
    }

    public void setStringB(String newString) {
        mStringB = newString;
    }
}
于 2012-08-20T20:20:10.470 に答える
0

はい、スレッドが 2 つのメソッドを同時に呼び出せるようにする場合は、2 つの個別のロックが必要です。これに関しては、改善すべき点は何もないと言えます。

ただし、あなたのgetInstance()メソッドは同期するブロックのサイズを最小化しようとしていますが、実際にはそれを達成していないことに気付きました。つまりsingletonInstance == null、同期ブロックの内部もチェックしています。なので、メソッド全体を で修飾したほうがいいと思いますsynchronized

そのメソッドのコードが短くなり、少し自然になります。

于 2012-08-20T19:59:34.293 に答える
0

どこから始めれば...

OK、ロックを再確認しました。(まだ) 壊れています。使用しないでください。シングルトンを使用する必要があると感じた場合 (そして、実際には一般的に悪い考えであり、代わりに依存性注入を使用します)、getter メソッドを同期し、すぐに戻ります。この場合、本当に膨大な数のコア (数千など) があり、常に getter メソッドを呼び出していない限り、競合する同期の可能性は非常に低くなります。

を に置き換えHashMapますConcurrentHashMap。Doug Lea は、あなたや私よりも並行コーディングが得意です。

文字列変数を揮発性としてマークし、同期しないでください。

于 2012-08-20T20:00:43.273 に答える