Search code examples
javaconcurrencyvolatilejava-memory-modelhappens-before

Does happen-before in Java new memory model also apply to the member of a object which is declared as volatile?


In the new Java memory model, any write to a variable is guaranteed to be completed before the next thread read it.

I wonder if this is also the case for variables that are member of this object.

for java memory model:

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

E.g.

public class VolatileTest {
    private volatile Map<String, Function> functionMap = new HashMap<>();

    public Function getFunction(String key) {
        Function function = this.functionMap.get(key);

        if (function == null) {
            //Is this guaranteed to be fully constructed? I don't think so.
            function = new Function(key);

            this.functionMap.put(key, function);
        }

        return function;
    }
}

Like above code, even by making functionMap volatile, it still doesn't guarantee the function object will be fully constructed before this method return.

Is my thinking right?

Also just for this topic, I'd like you guys to check is my thinking right for the following:

Like the below any write to the functionMap is guaranteed to be completed before changing the reference of functionMap, right? No matter how long the initializeMap methods take, the other thread will either see a null functionMap or a fully initialized functionMap?

public Map<String,Function> getFunctionMap (){
    Map<String, Function> tempMap = new HashMap<>();

    initalizeMap(tempMap); //fill in values

    // Above operation is guaranteed to be completed
    //   before changing the reference of this variable.
    this.functionMap = tempMap;

    // So here you will either see a null or a fully initialized map.
    // Is my understanding right?
    return this.functionMap;
}

Just to clarify above, above two examples are all in multi-thread environment and functionMap variables will be accessed by multiple thread.


Solution

  • This is exactly when ConcurrentHashMap should be used

    private final ConcurrentMap<String, Function> functionMap = new ConcurrentHashMap<>();
    
    public Function getFunction(String key) {
            Function function = functionMap.get(key);
            if (function == null) {
                function = new Function(key);
                Function oldFunction = functionMap.putIfAbscent(function);
                if (oldFunction != null) {
                     function = oldFunction;
                }
            }
            return function;
    }