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

rob*_*nkc 2 java multithreading synchronization hashmap

在我的应用程序中,我需要维护一个存储器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构造用于此类用例?

Mar*_*nik 6

您的map.put操作只会更新value字段HashMap$Node.这在HashMap结构一致性方面是安全的,但是在该value领域仍有数据竞争.如果您的值类型是一个简单的值类,如Integer,, Long或者Double,即使在数据竞争中也可以安全地取消引用它,但不能保证消费者会看到更新的分数.

一个干净的解决方法是更换您如LongAtomicLong作为价值类型.然后你的地图永远不会被更新,只有它的值会以线程安全的方式变异.

这是解决方案的大纲:

  1. 安全发布地图:

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

    void updateScore(Player p, long score) {
        map.get(p).set(score);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 阅读得分:

    long getScore(Player p) {
       return map.get(p).get();
    }
    
    Run Code Online (Sandbox Code Playgroud)