Reputation: 1348
In my application I need to maintain an in-memory HashMap
that stores list of userIds
along with their score
.
There is one Writer Thread that updates the score of the user based on business logic. And many Reader Threads read the score
of users from this map, ie, map.get(userId)
.
The list of userIds
is static, ie, no new users are added to the map.
As per JavaDoc If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
I am not making any structural changes (no additions / deletions). Do I need to use ConcurrentHashMap
or any other Synchronization
construct for such a use case?
Upvotes: 2
Views: 288
Reputation: 200206
Your map.put
operation will just update the value
field of HashMap$Node
. This is safe with respect to HashMap
's structural consistency, but there is nevertheless a data race on the value
field. If your value type is a simple value class like Integer
, Long
, or Double
, it is safe to dereference it even over a data race, but there is no guarantee that the consumer will ever see a score updated.
A clean solution to this is replacing your e.g. Long
with AtomicLong
as the value type. Then your map will never be updated, only its values will be mutated in a thread-safe manner.
This is the outline of solution:
Safely publish the map:
volatile Map<Player, AtomicLong> scores;
void publishScores() {
scores = unmodifiableMap(createScoresMap());
}
Update a score:
void updateScore(Player p, long score) {
map.get(p).set(score);
}
Read a score:
long getScore(Player p) {
return map.get(p).get();
}
Upvotes: 6