<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          美團面試拷打:ConcurrentHashMap 為何不能插入 null?HashMap 為何可以?

          共 4603字,需瀏覽 10分鐘

           ·

          2023-08-31 19:52

          JavaGuide 官方網站javaguide.cn

          周末的時候, 知識星球有一位小伙伴提了一些關于  ConcurrentHashMap 的問題,都是他最近面試遇到的。原提問如下(星球原貼地址:https://t.zsxq.com/11jcuezQs ):

          整個提問看著非常復雜,其實歸納來說就是兩個問題:

          1. ConcurrentHashMap 為什么 key 和 value 不能為 null?
          2. ConcurrentHashMap 能保證復合操作的原子性嗎?

          下面我會以此提供這兩個問題的詳細答案,希望對你有幫助。

          ConcurrentHashMap 為什么 key 和 value 不能為 null?

          ConcurrentHashMap 的 key 和 value 不能為 null 主要是為了避免二義性。null 是一個特殊的值,表示沒有對象或沒有引用。如果你用 null 作為鍵,那么你就無法區(qū)分這個鍵是否存在于 ConcurrentHashMap 中,還是根本沒有這個鍵。同樣,如果你用 null 作為值,那么你就無法區(qū)分這個值是否是真正存儲在 ConcurrentHashMap 中的,還是因為找不到對應的鍵而返回的。

          拿 get 方法取值來說,返回的結果為 null 存在兩種情況:

          • 值沒有在集合中 ;
          • 值本身就是 null。

          這也就是二義性的由來。

          具體可以參考 ConcurrentHashMap 源碼分析( https://javaguide.cn/java/collection/concurrent-hash-map-source-code.html)這篇文章。

          多線程環(huán)境下,存在一個線程操作該 ConcurrentHashMap 時,其他的線程將該 ConcurrentHashMap 修改的情況,所以無法通過 containsKey(key) 來判斷否存在這個鍵值對,也就沒辦法解決二義性問題了。

          與此形成對比的是,HashMap 可以存儲 null 的 key 和 value,但 null 作為鍵只能有一個,null 作為值可以有多個。如果傳入 null 作為參數(shù),就會返回 hash 值為 0 的位置的值。單線程環(huán)境下,不存在一個線程操作該 HashMap 時,其他的線程將該 HashMap 修改的情況,所以可以通過 contains(key)來做判斷是否存在這個鍵值對,從而做相應的處理,也就不存在二義性問題。

          也就是說,多線程下無法正確判定鍵值對是否存在(存在其他線程修改的情況),單線程是可以的(不存在其他線程修改的情況)。

          如果你確實需要在 ConcurrentHashMap 中使用 null 的話,可以使用一個特殊的靜態(tài)空對象來代替 null。

          public static final Object NULL = new Object();

          最后,再分享一下 ConcurrentHashMap 作者本人 (Doug Lea)對于這個問題的回答:

          The main reason that nulls aren't allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can't be accommodated. The main one is that if map.get(key) returns null, you can't detect whether the key explicitly maps to null vs the key isn't mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.

          翻譯過來之后的,大致意思還是單線程下可以容忍歧義,而多線程下無法容忍。

          ConcurrentHashMap 能保證復合操作的原子性嗎?

          ConcurrentHashMap 是線程安全的,意味著它可以保證多個線程同時對它進行讀寫操作時,不會出現(xiàn)數(shù)據(jù)不一致的情況,也不會導致 JDK1.7 及之前版本的 HashMap 多線程操作導致死循環(huán)問題。但是,這并不意味著它可以保證所有的復合操作都是原子性的,一定不要搞混了!

          復合操作是指由多個基本操作(如putgetremovecontainsKey等)組成的操作,例如先判斷某個鍵是否存在containsKey(key),然后根據(jù)結果進行插入或更新put(key, value)。這種操作在執(zhí)行過程中可能會被其他線程打斷,導致結果不符合預期。

          例如,有兩個線程 A 和 B 同時對 ConcurrentHashMap 進行復合操作,如下:

          // 線程 A
          if (!map.containsKey(key)) {
          map.put(key, value);
          }
          // 線程 B
          if (!map.containsKey(key)) {
          map.put(key, anotherValue);
          }

          如果線程 A 和 B 的執(zhí)行順序是這樣:

          1. 線程 A 判斷 map 中不存在 key
          2. 線程 B 判斷 map 中不存在 key
          3. 線程 B 將 (key, anotherValue) 插入 map
          4. 線程 A 將 (key, value) 插入 map

          那么最終的結果是 (key, value),而不是預期的 (key, anotherValue)。這就是復合操作的非原子性導致的問題。

          那如何保證 ConcurrentHashMap 復合操作的原子性呢?

          ConcurrentHashMap 提供了一些原子性的復合操作,如 putIfAbsentcomputecomputeIfAbsentcomputeIfPresentmerge等。這些方法都可以接受一個函數(shù)作為參數(shù),根據(jù)給定的 key 和 value 來計算一個新的 value,并且將其更新到 map 中。

          上面的代碼可以改寫為:

          // 線程 A
          map.putIfAbsent(key, value);
          // 線程 B
          map.putIfAbsent(key, anotherValue);

          或者:

          // 線程 A
          map.computeIfAbsent(key, k -> value);
          // 線程 B
          map.computeIfAbsent(key, k -> anotherValue);

          很多同學可能會說了,這種情況也能加鎖同步呀!確實可以,但不建議使用加鎖的同步機制,違背了使用 ConcurrentHashMap 的初衷。在使用 ConcurrentHashMap 的時候,盡量使用這些原子性的復合操作方法來保證原子性。

          推薦閱讀

          更多關于  ConcurrentHashMap 大家可以自行去 JavaGuide 官方網站(javaguide.cn)上進行閱讀,內容非常全面。并且,上面提到的這兩個問題后續(xù)也會同步上去。

          ··············  END  ··············

          ??專屬面試小冊/一對一交流/簡歷修改/專屬求職指南,歡迎加入 JavaGuide 知識星球 。下面是星球提供的部分資料:

          知識星球專屬優(yōu)惠卷

          ?? 近期文章精選



          ??如果本文對你有幫助的話,歡迎 點贊&在看&分享 ,這對我繼續(xù)分享&創(chuàng)作優(yōu)質文章非常重要。非常感謝!

          瀏覽 12682
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月天婷婷丁香综合视频 | 含羞草一区二区三区无码观看 | 国产高清免费视频 | 中文字幕无码毛片免费看 | 国产剧情一区二区av在线观看 |