【问题标题】:HashMap: safe for multithreaded access for multiple readers and one single writer?HashMap:对多个读者和一个作者的多线程访问安全吗?
【发布时间】:2012-09-16 02:39:38
【问题描述】:

我正在阅读 java.util.HashMap 的文档,上面写着:

如果多个线程同时访问此映射,并且至少有一个 线程在结构上修改映射,它必须是同步的 外部。

“it”是什么意思?“it”可以解释为修改地图的线程,也可以解释为地图本身。

“多线程读取安全”和“只有在有写入器时才在单线程上安全”两种情况都不是明智之举(至少对我而言),这让我相信调用“多读取器和单写入器”文档中的具体情况意味着该语句应该被解释为“安全地让多个线程读取和单个线程写入”,而不是“当你有一个作家时锁定一切”。

更重要的是,.Net 中的哈希表实现(明确地)记录为:

Hashtable 是线程安全的,可供多个读取线程和单个写入线程使用

(默认情况下,.Net 类不是线程安全的),因此“多个读取器线程和一个单个写入器线程”的情况肯定存在。

【问题讨论】:

  • 同步一个线程是没有意义的。您同步对象以控制线程的访问。这是基本的Java。我看不出 .NET 与它有什么关系。

标签: java concurrency hashmap


【解决方案1】:

当线程“在结构上修改映射”时,内部元素处于不确定状态,因此可能会影响读取。因此需要使用映射外部的一些方法来同步读取和写入。

也许 .Net 库的编写者在更新期间更小心地保持其内部结构处于确定状态。

【讨论】:

    【解决方案2】:

    地图本身。 HashMap 不是线程安全的。

    ConcurrentHashMap,是线程安全的映射。

    您也可以自己管理。代码可能如下所示

    class SomeClass {
    
        private Map<Object, Object> map = new HashMap<Object, Object>();
    
        public synchronized void put(Object key, Object value) {
            map.put(key, value);
        }
    
        public synchronized Object get(Object key) {
            return map.get(key);
        }
    }
    

    更安全,返回值对象的副本,避免意外行为。

    public synchronized ValueType get(Object key) {
        return map.get(key).clone(); // assume that the ValueType implements Cloneable
        // of course, you can return a copy in many ways you like
    }
    

    这将只允许put 方法修改地图。而且所有的操作都是线程安全的。

    【讨论】:

    • 嗨@scarcer。 “HashMap 不是线程安全的”声明并不完全正确。一个 HashMap 实例是:
      - 当所有线程都在做读操作时保证是线程安全的
      - 当多个线程同时做写操作时不安全
      - [上面这个问题] : 并发时,多个线程在读,一个线程在写
    • @daniel “当所有线程都在执行读取操作时,HashMap 实例保证是线程安全的”,这是不正确的。见马克的回答。
    • @daniel,Steve Kuo,这是我的看法。如果所有线程都在做读操作(这意味着不仅读取映射,还读取从映射中读取的元素),因为映射的结构和映射的元素都没有改变,当然我们可以期望每个线程都能获得相同的值。但是如果结构或元素本身发生了变化,它就不再是线程安全的了。最安全的方法是:同步你的读取方法,并返回值对象的副本。请看我的帖子。
    猜你喜欢
    • 2012-03-25
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多