- 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; }
- put
- ConcurrentHashMap:拋棄了原有的 Segment 分段鎖,而采用了 CAS + synchronized 來保證并發(fā)安全性。和HashMap的區(qū)別在于,
Node<K,V>中的V val和Node<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
- put
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)
