Do we need to make ConcurrentHashMap volatile?

We have a shared ConcurrentHashMap which is read and written by 2 threads.

class Test {
    private ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();

    Object read() {
        return map.get(object);
    }

    void write(Object key, Object object) {
        map.put(key, object);
    }
}

Do we need to make the map volatile so that writes of one thread are seen by the reader threads as soon as possible?

Is it possible that a put to the map in one thread is not seen or seen very late by a different thread?

Same question for HashMap.


Solution 1:

If you can make it final then do that. If you cannot make it final then yes you would need to make it volatile. volatile applies to the field assignment and if it's not final then there is a possibility (at least per the JMM) that a write of the CHM field by one thread may not be visible to another thread. To reiterate, this is the ConcurrentHashMap field assignment and not using the CHM.

That being said, you should really make it final.

Do we need to make the map volatile so that writes of one thread are seen by the reader threads as soon as possible?

If the writes you speak of are done using the mutation methods of the CHM itself (like put or remove) you making the field volatile doesn't have an effect. All memory visibility guarantees are done within the CHM.

Is it possible that a put to the map in one thread is not seen or seen very late by a different thread? Same question for HashMap.

Not for the ConcurrentHashMap. If you are using a plain HashMap concurrently, don't. See: http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html

Solution 2:

volatile applies happens-before semantics on reads and writes to the corresponding variable.

A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).

It has nothing to do with objects referenced by the variable's value. You're not modifying the variable, so you shouldn't* have any problems, unless(*) you're not safely publishing the Test object that is shared across threads.

As Lii suggests in the coments, assuming you don't take the right precautions, through final, volatile, or some other synchronization mechanism, the JMM allows a reference to an object to be made available before the object has been fully initialized by its constructor. As such, one of your threads could try to use the map field before it's been initialized (eg. it would see null). In that sense, the code could break.

Is it possible that a put to the map in one thread is not seen or seen very late by a different thread?

This is not possible, as the javadoc states, ConcurrentHashMap methods introduce appropriate memory barriers,

Retrievals reflect the results of the most recently completed update operations holding upon their onset. (More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.

HashMap, however, is not a thread-safe type. volatile wouldn't help here either because it controls changes to the variable, not the object referenced by the variable. You'll need external synchronization to protect put and get calls to a HashMap.