HashMap和ConcurrentHashMap

  • HashMap
    • put
      //put方法最終實(shí)現(xiàn)
      final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
          Node<K,V>[] tab; Node<K,V> p; int n, i;
          //判斷當(dāng)前桶是否為空,空的就需要初始化(resize 中會(huì)判斷是否進(jìn)行初始化)
          if ((tab = table) == null || (n = tab.length) == 0)
              n = (tab = resize()).length;
          //根據(jù)當(dāng)前 key 的 hashcode 定位到具體的桶中并判斷是否為空,為空表明沒有 Hash 沖突就直接在當(dāng)前位置創(chuàng)建一個(gè)新桶即可
          if ((p = tab[i = (n - 1) & hash]) == null)
              tab[i] = newNode(hash, key, value, null);
          else {
              Node<K,V> e; K k;
              //如果當(dāng)前桶有值( Hash 沖突),那么就要比較當(dāng)前桶中的 key、key 的 hashcode 與寫入的 key 是否相等,相等就賦值給 e,在后面的時(shí)候會(huì)統(tǒng)一進(jìn)行賦值及返回
              if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                  e = p;
              else if (p instanceof TreeNode) //如果當(dāng)前桶為紅黑樹,那就要按照紅黑樹的方式寫入數(shù)據(jù)
                  e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
              else {//如果是個(gè)鏈表,就需要將當(dāng)前的 key、value 封裝成一個(gè)新節(jié)點(diǎn)寫入到當(dāng)前桶的后面(形成鏈表)
                  for (int binCount = 0; ; ++binCount) {
                      if ((e = p.next) == null) {
                          p.next = newNode(hash, key, value, null);
                          if (binCount >= TREEIFY_THRESHOLD - 1) //接著判斷當(dāng)前鏈表的大小是否大于預(yù)設(shè)的閾值,大于時(shí)就要轉(zhuǎn)換為紅黑樹
                              treeifyBin(tab, hash);
                          break;
                      }
                      //如果在遍歷過程中找到 key 相同時(shí)直接退出遍歷
                      if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                          break;
                      p = e;
                  }
              }
              if (e != null) { // 如果 e != null 就相當(dāng)于存在相同的 key,那就需要將值覆蓋
                  V oldValue = e.value;
                  if (!onlyIfAbsent || oldValue == null)
                      e.value = value;
                  afterNodeAccess(e);
                  return oldValue;
              }
          }
          ++modCount;
          //最后判斷是否需要進(jìn)行擴(kuò)容
          if (++size > threshold)
              resize();
          afterNodeInsertion(evict);
          return null;
      }
      
    • get
      public V get(Object key) {
          Node<K,V> e;
          return (e = getNode(hash(key), key)) == null ? null : e.value;
      }
      
      final Node<K,V> getNode(int hash, Object key) {
          Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
          //首先將 key hash 之后取得所定位的桶
          if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {
              //否則判斷桶的第一個(gè)位置(有可能是鏈表、紅黑樹)的 key 是否為查詢的 key,是就直接返回 value
              if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
                  return first;
              //如果第一個(gè)不匹配,則判斷它的下一個(gè)是紅黑樹還是鏈表
              if ((e = first.next) != null) {
                  //紅黑樹就按照樹的查找方式返回值
                  if (first instanceof TreeNode)
                      return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                  do {//按照鏈表的方式遍歷匹配返回值
                      if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                          return e;
                  } while ((e = e.next) != null);
              }
          }
          //如果桶為空則直接返回 null 
          return null;
      }
      
  • ConcurrentHashMap:拋棄了原有的 Segment 分段鎖,而采用了 CAS + synchronized 來保證并發(fā)安全性。和HashMap的區(qū)別在于,Node<K,V>中的V valNode<K,V> next都用volatile關(guān)鍵字修飾了,保證了兩個(gè)值的可見性和有序性
    • put
      final V putVal(K key, V value, boolean onlyIfAbsent) {
         if (key == null || value == null) 
              throw new NullPointerException();
         int hash = spread(key.hashCode());
         int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
             Node<K,V> f; int n, i, fh;
             //判斷是否需要初始化
             if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//f 即為當(dāng)前 key 定位出的 Node,如果為空表示當(dāng)前位置可以寫入數(shù)據(jù),利用 CAS 嘗試寫入,失敗則自旋保證成功
                 if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))
                     break;
             }
             else if ((fh = f.hash) == MOVED)//如果當(dāng)前位置的 hashcode == MOVED == -1,則需要進(jìn)行擴(kuò)容
                 tab = helpTransfer(tab, f);
             else {
                 V oldVal = null;
                 synchronized (f) {//如果都不滿足,則利用 synchronized 鎖寫入數(shù)據(jù)
                     if (tabAt(tab, i) == f) {
                         if (fh >= 0) {
                             binCount = 1;
                             for (Node<K,V> e = f;; ++binCount) {
                                 K ek;
                                 if (e.hash == hash &&
                                     ((ek = e.key) == key ||
                                      (ek != null && key.equals(ek)))) {
                                     oldVal = e.val;
                                     if (!onlyIfAbsent)
                                         e.val = value;
                                     break;
                                 }
                                 Node<K,V> pred = e;
                                 if ((e = e.next) == null) {
                                     pred.next = new Node<K,V>(hash, key,
                                                               value, null);
                                     break;
                                 }
                             }
                         }
                         else if (f instanceof TreeBin) {
                             Node<K,V> p;
                             binCount = 2;
                             if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                            value)) != null) {
                                 oldVal = p.val;
                                 if (!onlyIfAbsent)
                                     p.val = value;
                             }
                         }
                     }
                 }
                 if (binCount != 0) {
                      //如果數(shù)量大于 TREEIFY_THRESHOLD 則要轉(zhuǎn)換為紅黑樹
                     if (binCount >= TREEIFY_THRESHOLD)
                         treeifyBin(tab, i);
                     if (oldVal != null)
                         return oldVal;
                     break;
                 }
             }
         }
         addCount(1L, binCount);
         return null;
      }
      
    • get
        public V get(Object key) {
            Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
            int h = spread(key.hashCode());
            if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) {
                 //根據(jù)計(jì)算出來的 hashcode 尋址,如果就在桶上那么直接返回值
                if ((eh = e.hash) == h) {
                    if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                        return e.val;
                }
                else if (eh < 0)//如果是紅黑樹那就按照樹的方式獲取值
                    return (p = e.find(h, key)) != null ? p.val : null;
                //按照鏈表的方式遍歷獲取值
                while ((e = e.next) != null) {
                    if (e.hash == h &&
                        ((ek = e.key) == key || (ek != null && key.equals(ek))))
                        return e.val;
                }
            }
            return null;
        }
        ```


更多文章:
[CSDN博客](https://blog.csdn.net/weixin_41131531/article/list/1?)
[簡書博客](http://www.itdecent.cn/u/835dab65e416)
公眾號(hào):代碼小搬運(yùn)
![代碼小搬運(yùn).jpg](https://upload-images.jianshu.io/upload_images/20200230-0d78171f88c290ce.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容