简体   繁体   English

当两个线程试图将相同的键值放入并发哈希表时会发生什么

[英]What happens when two threads trying to put the same key value in concurrent hashmap

Imagine there are two threads A, B that are going to put two different values in the map, v1 and v2 respectively, having the same key. 想象有两个线程A,B将在映射中分别放置两个不同的值v1和v2,它们具有相同的键。 The key is initially not present in the map Thread A calls containsKey and finds out that the key is not present, but is immediately suspended Thread B calls containsKey and finds out that the key is not present, and has the time to insert its value v2 该键最初在映射中不存在。线程A调用containsKey并发现该键不存在,但立即挂起。线程B调用containsKey并发现该键不存在,并有时间插入其值v2

When thread A is back,what happens?. 当线程A返回时,会发生什么? I assume that,It calls put method which in turn calls putIfAbsent But the key is already there inserted by thread B.so thread A will not override the value 我假设,它调用了put方法,该方法又调用了putIfAbsent但密钥已经被线程B插入。因此线程A将不会覆盖该值

But from this link i found that Thread A resumes and inserts v1, "peacefully" overwriting (since put is threadsafe) the value inserted by thread B Is ConcurrentHashMap totally safe? 但是从这个链接中,我发现线程A恢复并插入v1,“和平地”覆盖(因为put是线程安全的),线程B插入的值是否完全安全?ConcurrentHashMap是否完全安全?

Here's what ConcurrentHashMap will do for you: 这是ConcurrentHashMap将为您做的事情:

(1) Key/value pairs won't mysteriously appear in the map. (1)键/值对不会神秘地出现在地图中。 If you try to get a value for some key, You are guaranteed to get a value that some thread in your program stored with that key, or you will get a null reference if no thread has ever stored a value for that key. 如果尝试获取某个键的值,则可以确保获取程序中某个线程与该键一起存储的值,如果没有线程为该键存储值,则将获得null引用。

(2) key/value pairs won't mysteriously disappear from the map. (2)键/值对不会神秘地从地图上消失。 If you call get(K) for some K that previously had a value, and a null reference comes back, it's because some thread in your program stored the null. 如果您为以前具有值的K调用get(K),并且返回空引用,那是因为程序中的某些线程存储了空值。

(3) It won't deadlock or hang or crash your program. (3)它不会死锁,挂起或崩溃您的程序。

Here's what ConcurrentHashMap will not do for you: 这是ConcurrentHashMap 不能为您提供的功能:

It won't make your program "thread safe". 它不会使您的程序“线程安全”。

The most important thing to remember about thread safety is this: Building a module or a program entirely from "thread-safe" components will not make the the program or module "thread-safe". 关于线程安全性要记住的最重要的事情是:完全从“线程安全”组件构建模块或程序不会使程序或模块“线程安全”。 Your question is a perfect example of why not. 您的问题是为什么不这样做的一个很好的例子。

ConcurrentHashMap is a thread-safe object. ConcurrentHashMap是线程安全的对象。 No matter how many threads access it at the same time, it will keep the promises (1), (2), and (3) that I listed above. 无论有多少线程同时访问它,它都会遵守我上面列出的承诺(1),(2)和(3)。 But if two of your program's threads each try put a different value into the map for the same key at the same time, that's a data race . 但是,如果您程序的两个线程各自尝试同时为同一键将不同的值放入映射中,那就是数据竞争 When some other thread later looks up that key, the value that it gets will depend on which thread won the race. 当其他某个线程稍后查找该键时,它获得的值将取决于哪个线程赢得了竞争。

If the correctness of your program depends on which thread wins a data race, then your program is not "thread-safe" even though the objects from which it was built are called "thread safe". 如果程序的正确性取决于哪个线程赢得了数据竞争,那么即使从中构建程序的对象称为“线程安全”,您的程序也不是“线程安全的”。

Both threads will need to use putIfAbsent . 两个线程都需要使用putIfAbsent From the docs (with emphasis added) on putIfAbsent(key, value) : docs (添加重点)到putIfAbsent(key, value)

This is equivalent to 这相当于

  if (!map.containsKey(key)) return map.put(key, value); else return map.get(key); 

except that the action is performed atomically. 除了动作是原子执行的。

A call to put() does not eventually result in a call to putIfAbsent() (as your question seems to suggest); 调用put()最终不会导致调用putIfAbsent() (正如您的问题似乎暗示的那样); it's the other way around. 相反。

Trying to achieve the same effect with separate calls to containsKey() and put() will require that you use your own higher-level synchronization blocks. 尝试通过分别调用containsKey()put()来实现相同的效果,将需要您使用自己的更高级别的同步块。

A robust implementation of a concurrent hash map would use synchronization to make calling containsKey() atomic with the insertion of a new map entry. 并发哈希映射的可靠实现将使用同步,以在插入新映射条目的情况下使调用containsKey()原子。 If thread A were suspended after calling containsKey() , thread B would find that it could not obtain the lock and therefore could not call containsKey() as you describe. 如果线程A在调用containsKey()之后挂起,则线程B会发现它无法获取该锁,因此无法按照您所描述的那样调用containsKey()

final V put(K key, int hash, V value, boolean onlyIfAbsent) {
     HashEntry<K,V> node = tryLock() ? null :
         scanAndLockForPut(key, hash, value);
     V oldValue;
     try {
         HashEntry<K,V>[] tab = table;
         int index = (tab.length - 1) & hash;
         HashEntry<K,V> first = entryAt(tab, index);
         for (HashEntry<K,V> e = first;;) {
            if (e != null) {
                 K k;
                 if ((k = e.key) == key ||
                     (e.hash == hash && key.equals(k))) {
                     oldValue = e.value;
                     if (!onlyIfAbsent) {
                        e.value = value;
                        ++modCount;
                     }
                     break;
                 }
                 e = e.next;
             }
            else {
                if (node != null)
                   node.setNext(first);
               else
                    node = new HashEntry<K,V>(hash, key, value, first);
                 int c = count + 1;
                if (c > threshold && tab.length < MAXIMUM_CAPACITY)
                    rehash(node);
                else
                    setEntryAt(tab, index, node);
                 ++modCount;
                 count = c;
               oldValue = null;
                 break;
             }
      }
   } finally {
         unlock();
     }
     return oldValue;
 }

found answer from internal implementation of put method, put will override the value, when we try to add the key which is already existing. 从put方法的内部实现中找到答案,当我们尝试添加已经存在的键时,put将覆盖该值。

暂无
暂无

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

相关问题 当两个线程尝试修改/访问 Concurrent HashMap 中的同一个键时会发生什么? - What happens when two threads try to modify/ access the same key in Concurrent HashMap? 当两个线程试图修改/访问HashMap中的相同键时会发生什么? - What happens when two threads try to modify/access the same key in HashMap? 如果两个不同的线程(比如两个不同的 https 请求)尝试在并发哈希图中同时修改/更新相同的键,会发生什么? - What will happen if two different threads(say two different https requests) try to modify/update the same key at same time in the concurrent hashmap? 将弱引用的对象放入HashMap作为键时会发生什么? - What happens when weak referenced object is put itno HashMap as key? 在两个线程中使用相同的Hashmap时,Hashmap中的并发修改异常 - Concurrent Modification Exception in Hashmap while using the same Hashmap in two threads 当少数线程尝试调用相同的同步方法时会发生什么? - What happens when few threads trying to call the same synchronized method? 通过两个线程并发修改HashMap - Concurrent modification of HashMap by two threads 当两个并发线程试图从CopyOnWriteArrayList中删除元素时会发生什么? java的 - What Happens When two concurrent threads try to remove elements from a CopyOnWriteArrayList? java 同时添加到 ArrayList 的并发线程 - 会发生什么? - Concurrent threads adding to ArrayList at same time - what happens? 当两个线程同时调用相同的静态方法时会发生什么? - What happens when two threads call the same static method at the same time?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM