如果只有一个writer线程并且没有对映射进行结构修改,那么我们是否需要同步java HashMap get
在我的应用程序中,我需要在内存中维护一个如果只有一个writer线程并且没有对映射进行结构修改,那么我们是否需要同步java HashMap get,java,multithreading,hashmap,synchronization,Java,Multithreading,Hashmap,Synchronization,在我的应用程序中,我需要在内存中维护一个HashMap,它存储用户ID列表及其分数 有一个Writer线程根据业务逻辑更新用户的分数。许多读者线程从这个地图上读取用户的分数,即map.get(userId) userid的列表是静态的,即没有新用户添加到地图中 根据JavaDoc的说法,如果多个线程同时访问一个哈希映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。 我没有进行任何结构更改(没有添加/删除)。对于这种用例,我是否需要使用ConcurrentHashMap或任何其他同
HashMap
,它存储用户ID列表及其分数
有一个Writer线程根据业务逻辑更新用户的分数。许多读者线程从这个地图上读取用户的分数,即map.get(userId)
userid的列表是静态的,即没有新用户添加到地图中
根据JavaDoc的说法,如果多个线程同时访问一个哈希映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。
我没有进行任何结构更改(没有添加/删除)。对于这种用例,我是否需要使用ConcurrentHashMap
或任何其他同步
构造 您的map.put
操作将只更新HashMap$Node
的value
字段。这对于HashMap
的结构一致性来说是安全的,但是在value
字段上仍然存在数据竞争。如果您的值类型是一个简单的值类,如Integer
、Long
或Double
,即使在数据竞争中也可以安全地取消对它的引用,但不能保证消费者会看到分数更新
一个干净的解决方案是用AtomicLong
替换您的值类型,例如Long
。然后你的地图将永远不会被更新,只有它的值会以线程安全的方式被改变
这是解决方案的概要:
安全发布地图:
volatile Map<Player, AtomicLong> scores;
void publishScores() {
scores = unmodifiableMap(createScoresMap());
}
读一段乐谱:
long getScore(Player p) {
return map.get(p).get();
}
如果没有正确的同步,就不能保证“读取”线程将读取正确的值,但在您的情况下不会发生ConcurrentModificationException。为了研究良好的并发实践,我建议使用以下资源:您可以有一个userId->wrapper
的映射,其中wrapper包含一个volatile scrore
。简单地读写score
就可以了。
long getScore(Player p) {
return map.get(p).get();
}