在我的应用程序中,我需要维护一个内存HashMap
,它存储userIds
的列表及其score
。
有一个Writer Thread根据业务逻辑更新用户的分数。许多Reader Threads从此地图中读取score
个用户,即map.get(userId)
。
userIds
列表是静态的,即没有新用户添加到地图中。
根据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.
我没有进行任何结构更改(没有添加/删除)。对于这样的用例,我是否需要使用ConcurrentHashMap
或任何其他Synchronization
构造?
答案 0 :(得分:6)
您的map.put
操作只会更新value
的{{1}}字段。就HashMap$Node
的结构一致性而言,这是安全的,但HashMap
字段仍有数据竞争。如果您的值类型是一个简单的值类,如value
,Integer
或Long
,即使在数据竞争中也可以取消引用它,但不能保证消费者会永远看到分数更新。
一个干净的解决方案是替换你的Double
Long
作为值类型。然后你的地图永远不会被更新,只有它的值会以线程安全的方式变异。
这是解决方案的概要:
安全发布地图:
AtomicLong
更新分数:
volatile Map<Player, AtomicLong> scores;
void publishScores() {
scores = unmodifiableMap(createScoresMap());
}
阅读得分:
void updateScore(Player p, long score) {
map.get(p).set(score);
}