javaimmutabilityjava-memory-model

Are operations to ImmutableCollection saved to non-final field thread-safe


If in my class I have a field of type ImmutableMap like:

private ImmutableMap<String, State> states = ImmutableMap.of();

And there is 1 reader thread and 1 writer thread

Reader reads by calling methods like get on states with no synchronized or any kinds of barriers.

Writer thread writes by reassigning states to new variables like states = ImmutableMap.of(...) in a synchronized method (which, as far as I know, provides no guarantee of visibility in the other threads if they have no read memory barriers).

So the whole thing looks like this:

State read(String key) {
    return states.get(key);
}

synchronized void write(String key, State value) {
    var hashMap = new HashMap<String, State>();
    states.forEach(hashMap::put);
    hashMap.put(key, value);
    states = ImmutableMap.of(hashMap);
}

Is it true, that reader, when reading from a field states gets a valid value of states, that existed at one point of the time (linearizability is present)? Can reader thread read some nonsense when reading value of states due to compiler reordering?


Solution

  • Is it true, that reader, when reading from a field states gets a valid value of states, that existed at one point of the time (linearizability is present)? Can reader thread read some nonsense when reading value of states due to compiler reordering?

    In your example each read of states has no happens-before ordering with writes to states.
    According to the JMM that means every read is allowed to return any of the writes to states that happen anytime during the program execution.
    This includes writes to states that happen later (in wall-clock time) in the same execution.
    This also includes null - the default initialization value for states.

    Here's the quote from the JLS:

    Informally, a read r is allowed to see the result of a write w if there is no happens-before ordering to prevent that read.

    To sum up: