如果只有一个编写器线程并且没有对地图进行结构修改,我们是否需要同步java HashMap获取

时间:2016-11-23 14:08:45

标签: java multithreading hashmap synchronization

在我的应用程序中,我需要维护一个内存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构造?

1 个答案:

答案 0 :(得分:6)

您的map.put操作只会更新value的{​​{1}}字段。就HashMap$Node的结构一致性而言,这是安全的,但HashMap字段仍有数据竞争。如果您的值类型是一个简单的值类,如valueIntegerLong,即使在数据竞争中也可以取消引用它,但不能保证消费者会永远看到分数更新。

一个干净的解决方案是替换你的Double Long作为值类型。然后你的地图永远不会被更新,只有它的值会以线程安全的方式变异。

这是解决方案的概要:

  1. 安全发布地图:

    AtomicLong
  2. 更新分数:

    volatile Map<Player, AtomicLong> scores;
    
    void publishScores() {
       scores = unmodifiableMap(createScoresMap());
    }
    
  3. 阅读得分:

    void updateScore(Player p, long score) {
        map.get(p).set(score);
    }