2

In the book "Java Concurrency in Practice" is mentioned that the following code is not threadsafe:

@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;
    }
}

It is not thread safe because because: - one thread can create new instance of Resource - another thread at the same time in the "if" condition can get not empty reference but the object of Resource will not be completly initialized

In this question is similar code. Resources are stored in concurentHashMap and people say that it is threadSafe. Something like this:

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;
    }
}

Why does storing the values in ConcurrentHashMap make the code threadSafe? I think that it is still possible that the ComplexObject won't be completely initialized and this "partial object" will be saved in the map. And other threads will be reading partial not fully initialized objects.

I think I know what is "happens-before", I've analyzed code in JDK 8.0_31 and I still don't know the answer.

I am aware of the functions like computeIfAbsent, putIfAbsent. I know that this code can be written differently. I just wan't know details which make this code threadsafe.

4

1 回答 1

4

发生之前实际上是这里的关键。边缘从延伸到后续发生之前发生,因此您检索的对象至少与它存储在地图中时一样最新。map.put(key, object)map.get(key)

于 2015-03-09T21:07:42.460 回答