2

本「Java Concurrency in Practice」では、次のコードはスレッドセーフではないことが言及されています。

@NotThreadSafe
public class DoubleCheckedLocking {

    private static Resource resource;

    public static Resource getInstance(){
        if(resource == null){
            synchronized (DoubleCheckedLocking.class){
                if(resource == null)
                    resource = new Resource();
            }
        }
        return resource;
    }
}

次の理由により、スレッドセーフではありません: - 1 つのスレッドがリソースの新しいインスタンスを作成できる - 「if」条件で同時に別のスレッドが空の参照を取得できないが、リソースのオブジェクトが完全に初期化されない

この質問には同様のコードがあります。リソースは concurentHashMap に格納され、人々はそれがスレッドセーフであると言います。このようなもの:

public class DoubleCheckedLocking2 {

    private static ConcurrentHashMap<String, ComplexObject> cache = new ConcurrentHashMap<String, ComplexObject>();

    public static ComplexObject getInstance(String key) {
        ComplexObject result = cache.get(key);
        if (result == null) {
            synchronized (DoubleCheckedLocking2.class) {
                ComplexObject currentValue = cache.get(key);
                if (currentValue == null) {
                    result = new ComplexObject();
                    cache.put(key, result);
                } else {
                    result = currentValue;
                }
            }
        }
        return result;
    }
}

ConcurrentHashMap に値を格納するとコードが threadSafe になるのはなぜですか? ComplexObject が完全に初期化されず、この「部分オブジェクト」がマップに保存される可能性はまだあると思います。また、他のスレッドは、完全に初期化されていない部分的なオブジェクトを読み取ります。

「前に起こる」とは何かを知っていると思います。JDK 8.0_31 のコードを分析しましたが、まだ答えがわかりません。

computeIfAbsentputIfAbsentなどの関数を認識しています。このコードは別の方法で記述できることを知っています。このコードをスレッドセーフにする詳細を知りたくないだけです。

4

1 に答える 1

4

ここで鍵となるのは、実際に起こる前です。エッジが から後続のに拡張する前に発生するため、取得するオブジェクトは少なくともマップに格納された時点と同じくらい最新です。map.put(key, object)map.get(key)

于 2015-03-09T21:07:42.460 に答える