当两个线程试图修改/访问HashMap中的相同密钥时会发生什么? [英] What happens when two threads try to modify/access the same key in HashMap?

查看:108
本文介绍了当两个线程试图修改/访问HashMap中的相同密钥时会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在并发环境中,应使用ConcurrentHashMap.但是Java对普通的HashMap保证了什么?

In concurrent environment ConcurrentHashMap should be used. But what did java promise for normal HashMap?

Map map = new HashMap();

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

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

当尝试通过map.get("a")获取值时,是否可以保证地图不会损坏并且返回值必须在12中?

when try to get value by map.get("a"), will I be promised that the map will not broken and the return value must in 1 or 2?

推荐答案

据我了解,问题在于并发场景中会发生什么,而不是HashMap是否合适(众所周知的不合适).

If I understood, the question is about what happens in a concurrent scenario and not if the HashMap is suitable or not (what is widely known as not suitable).

了解在这种非常不理想的情况下会发现哪种问题的最佳方法是分析

The best way to realize what kind of problems can be found in a very undesirable scenario like that is to analyse the source code. For example, in the openjdk 1.6 implementation:

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

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

In the absence o synchronisation mechanism in this method and in the attributes, one or more of the following problems can occurs:

1)不确定的回报

该行:

return oldValue;

线程1的结果可以是旧值(在调用线程1和2之前),可以是2或为空.它取决于线程2的addEntry(hash,key,value,i)是否完全运行.当然,线程2也存在同样的问题.

results for thread 1 can be the old value (before thread 1 and 2 calls), can be 2 or null. Its dependes if the Thread 2 addEntry(hash, key, value, i) completely rans or not. The same problem with thread 2, of course.

2)不确定的索引和重复的键

2) undetermined index and duplicated keys

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

取决于table.length.因此,根据该哈希是否存在先前的值,i索引可以在另一个线程中的两次调用中有所不同(取决于另一个线程中addEntry(hash,key,value,i)的执行情况.

depends over the table.length. So, depending if there exist a previous value for this hash or not, the i index can diverge for both calls (depending on the execution of addEntry(hash, key, value, i) in the another thread.

3)大小和一致性都破了

3) Broken size and consistence

预计put("a",...)的连续调用不会更改映射的大小(至少在没有键"a"的条目的第一次调用之后).但是,根据两个线程的种族条件,地图尺寸一致性可能会破坏,即键集的大小与地图大小的大小不同.其他用于散列密钥的变量,因为modCount可能会变得前后不一致,破坏了put和get的调用.

It is expected that successive calls of put("a",...) do not change the size of the map (at least after the first call when there is no entry for key "a"). But, depending on the race conditions of the two threads, the map size consistence can become broken, i.e, the size of the keyset is different of the size of map size. Other variables used to hash the key, as modCount can become inconsistent broken future calls of put and get.

因此,在问题注解中如何恰当地说,由于意外的行为和内部结构的损坏,完全不建议在并发场景中使用Map.

So, how was properly said in the question commentaries, the use of a Map in a concurrent scenario is fully disencoraged due the unexpected behaviour and damage to the inner structure.

这篇关于当两个线程试图修改/访问HashMap中的相同密钥时会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆