繁体   English   中英

当两个线程试图修改/访问HashMap中的相同键时会发生什么?

[英]What happens when two threads try to modify/access the same key in HashMap?

在并发环境中应该使用ConcurrentHashMap 但java为普通的HashMap做了什么?

Map map = new HashMap();

// thread 1
map.put("a", 1)

// thread 2
map.put("a", 2)

当我试图通过map.get("a")获取值时,我是否会承诺地图不会被破坏,返回值必须在12

如果我理解,问题是关于并发场景中发生了什么,而不是HashMap是否合适(众所周知的不适合)。

在非常不合适的场景中发现可以找到哪种问题的最佳方法是分析源代码 例如,在openjdk 1.6实现中:

public V More ...put(K key, V value) {
     if (key == null)
         return putForNullKey(value);
     int hash = hash(key.hashCode());
     int i = indexFor(hash, table.length);
     for (Entry<K,V> e = table[i]; e != null; e = e.next) {
         Object k;
         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
             V oldValue = e.value;
             e.value = value;
             e.recordAccess(this);
             return oldValue;
         }
    }

     modCount++;
     addEntry(hash, key, value, i);
     return null;
 }

在此方法和属性中缺少同步机制时,可能会出现以下一个或多个问题:

1)非确定性回报

这条线:

return oldValue;

线程1的结果可以是旧值(在线程1和2调用之前),可以是2或null。 如果线程2 addEntry(散列,键,值,i)完全发生或不发生,则它依赖于它。 当然,线程2也存在同样的问题。

2)未确定的索引和重复的密钥

int i = indexFor(hash, table.length);

取决于table.length。 因此,根据是否存在此哈希的先前值,i索引可以为两个调用分叉(取决于另一个线程中addEntry(哈希,键,值,i)的执行。

3)破碎的尺寸和一致性

预期连续调用put(“a”,...)不会改变映射的大小(至少在第一次调用之后没有键“a”的条目)。 但是,根据两个线程的竞争条件 ,地图大小一致性可能会被破坏,即, 键集的大小与地图大小的大小不同。 用于散列键的其他变量,因为modCount可能会变得不一致,以及将来调用put和get。

因此,如何在问题评论中正确地说,由于意外行为和内部结构的损坏,在并发场景中使用Map是完全消除的。

哈希映射不是线程安全的,不能保证会发生什么。 它取决于线程的执行顺序。

不在读取模式下对HashMap的多线程访问可能导致未定义的行为。

使用同步构造Collections.synchronizedMap(new HashMap())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM