What is the preferred way to change the value in ConcurrentHashMap?

Let's say I have a parallel card with a high reading level, low write and the need to store application data:

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

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

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

If I need to change the data, I must:

A) Make the data class objects immutable and then perform the put operation every time a change is required for the 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 data class objects mutable but thread safe with mutable fields, atomic links, or trailing parallel fields, and simply modify the object as necessary:

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

C) None of the above

+4
source share
3 answers

A) is the best option for two reasons:

  • Since reading more often in your script, you should reduce the amount of overhead for them. Adding additional synchronization (eg, volatile ) works against you in this case.
  • Using mutable objects with additional customizable protections (which may have bugs), you win pretty much to make your life easier using ConcurrentHashMap .
+7
source

Just a thought. You indicated that the write speed is low, but for the sake of argument, several simultaneous write / call operations of the changeData method are changeData . Then it is possible that the thread that called the method last last ends first (in both approaches).

If your application logic assumes that the insertion order is followed, this may lead to incorrect results. In this case, the body of the changeData method is your critical section , which by definition means that it should not be executed at the same time.

The definition of a critical section is very sensitive to the semantics of the application area and the structure of the code, so I cannot say whether this method should be considered a critical section. Having guessed the variable names, and suppose your map is a cache of user data from the database, I would suggest that you can ignore this answer. But think about it though :)

If all entries go through this method, it will be a code sketch (you can use the implementation of an unsafe map implementation):

 public void changeData(UUID oldId, Foo newInfo) { synchronized(SomeClass.class) { // global lock //update logic } } 

This is just a sketch to illustrate the essence of the course. Chances are you can use some of the parallel Java constructs if this is a problem.

+3
source

If you have the opportunity to create an immutable class, you will be much better off with your #A implementation: in-place modifications are much more difficult to implement and maintain.

Sometimes switching to an unchangeable route may not be an option, because of the need to often make changes to a relatively large object. In this case, you may need to reconsider the parallel hash map application for your design, because the fact that it is synchronized does not give you too much benefit.

+2
source

Source: https://habr.com/ru/post/1498039/


All Articles