【问题标题】:Do we need to synchronize java HashMap gets if there is only one writer thread and no structural modifications to the map are done如果只有一个写入线程并且没有对映射进行结构修改,我们是否需要同步 java HashMap 获取
【发布时间】:2016-11-23 14:08:44
【问题描述】:

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

【问题讨论】:

  • 如果没有适当的同步,无法保证“读取”线程将读取正确的值
  • Race condition 仍然会发生,但在您的情况下不会发生 ConcurrentModificationException 。为了研究良好的并发实践,我推荐这个资源:jcip.net
  • 您可以拥有userId->wrapper 的映射,其中包装器包含volatile scrore。简单地读写score就可以了。

标签: java multithreading hashmap synchronization


【解决方案1】:

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

一个干净的解决方案是替换你的例如LongAtomicLong 作为值类型。那么您的地图将永远不会被更新,只会以线程安全的方式改变它的值。

这是解决方案的大纲:

  1. 安全发布地图:

    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();
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-12
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    相关资源
    最近更新 更多