java - 如果只有一个writer线程并且没有对map进行结构修改,我们是否需要同步java HashMap gets

标签 java multithreading hashmap synchronization

在我的应用程序中,我需要维护一个内存中的HashMap,它存储userIds 列表及其分数

有一个 Writer Thread 根据业务逻辑更新用户的分数。并且许多Reader Threads从该 map 中读取用户的score,即map.get(userId)

userIds 列表是静态的,即没有新用户添加到 map 中。

根据 JavaDoc 如果多个线程同时访问 HashMap ,并且至少有一个线程在结构上修改映射,则必须在外部进行同步。

我没有进行任何结构性更改(没有添加/删除)。对于这样的用例,我是否需要使用 ConcurrentHashMap 或任何其他同步构造?

最佳答案

您的map.put操作只会更新HashMap$Nodevalue字段。就 HashMap 的结构一致性而言,这是安全的,但 value 字段上仍然存在数据竞争。如果您的值类型是一个简单的值类,例如 IntegerLongDouble,则即使在数据争用中也可以安全地取消引用它,但不能保证消费者会看到更新的分数。

对此的一个干净的解决方案是替换您的例如LongAtomicLong 作为值类型。那么你的 map 将永远不会更新,只有它的值会以线程安全的方式发生变化。

这是解决方案的概要:

  1. 安全发布 map :

    volatile Map<Player, AtomicLong> scores;
    
    void publishScores() {
       scores = unmodifiableMap(createScoresMap());
    }
    
  2. 更新分数:

    void updateScore(Player p, long score) {
        map.get(p).set(score);
    }
    
  3. 读取乐谱:

    long getScore(Player p) {
       return map.get(p).get();
    }
    

关于java - 如果只有一个writer线程并且没有对map进行结构修改,我们是否需要同步java HashMap gets,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40766688/

相关文章:

java - Java中Double类型的总和

java - 如何使用 MongoDB API Java 在数组中查找文档?

c# - 使用 Task.Factory.StartNew 时更新 UI 标签

linux - 在 linux 上使用 mingw 交叉编译 c++11 线程

java - Java 中发生冲突时迭代 hashmap

java-删除字符串列表中的子字符串

java - springSecurityFilterChain 正在创建异常

multithreading - 在多线程中解析时,输入字符串的格式不正确

java - 如何将HashMap转换为自己类型的数组?

java - 如何允许在此 Java 代码中检查两个以上的单词