Search code examples
javaconcurrencythread-safetyconcurrenthashmap

What is the preferred way to modify a value in ConcurrentHashMap?


Let's say I have a Concurrent Map that is high-read, low-write, and needs to store application data:

ConcurrentMap<UUID, Data> map = new ConcurrentHashMap<UUID, Data>();

Then, during startup and through user input, data is added to the map:

public void createData(Data newData) {
    map.put(newId, newData); // etc...
}

If I then need to change the data, should I:

A) Make the Data class objects immutable, and then conduct a put operation every time a change is needed for a Data object:

public void changeData(UUID oldId, Foo newInfo) {
    Data oldData = map.get(oldId);
    Data newData = new Data(oldData, newInfo); // Constructor for demo only
    map.put(newData);
    saveToDatabase(newData);
}

B) Make the Data class objects mutable yet thread-safe with volatile fields, atomic references or final concurrent fields, and simply modify the object as needed:

public void changeData(UUID oldId, Foo newInfo) {
    Data data = map.get(id);
    data.changeSomething(newInfo);
    saveToDatabase(data);
}

C) None of the above


Solution

  • A) is the better option, for two reasons:

    1. Since in your scenario reads are more frequent, you should reduce the amount of overhead for them. Adding additional synchronization (such as volatile) works against you in this case.
    2. By using mutable objects with additional custom safeguards (which may have bugs) you're pretty much defeating the point of making your life easier by using ConcurrentHashMap.