- HashMap
- put
//put方法最终实现 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //判断当前桶是否为空,空的就需要初始化(resize 中会判断是否进行初始化) if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //根据当前 key 的 hashcode 定位到具体的桶中并判断是否为空,为空表明没有 Hash 冲突就直接在当前位置创建一个新桶即可 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; //如果当前桶有值( Hash 冲突),那么就要比较当前桶中的 key、key 的 hashcode 与写入的 key 是否相等,相等就赋值给 e,在后面的时候会统一进行赋值及返回 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) //如果当前桶为红黑树,那就要按照红黑树的方式写入数据 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else {//如果是个链表,就需要将当前的 key、value 封装成一个新节点写入到当前桶的后面(形成链表) for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) //接着判断当前链表的大小是否大于预设的阈值,大于时就要转换为红黑树 treeifyBin(tab, hash); break; } //如果在遍历过程中找到 key 相同时直接退出遍历 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // 如果 e != null 就相当于存在相同的 key,那就需要将值覆盖 V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; //最后判断是否需要进行扩容 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) { //否则判断桶的第一个位置(有可能是链表、红黑树)的 key 是否为查询的 key,是就直接返回 value if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k)))) return first; //如果第一个不匹配,则判断它的下一个是红黑树还是链表 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 来保证并发安全性。和HashMap的区别在于,
Node<K,V>
中的V val
和Node<K,V> next
都用volatile
关键字修饰了,保证了两个值的可见性和有序性- 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 即为当前 key 定位出的 Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,失败则自旋保证成功 if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null))) break; } else if ((fh = f.hash) == MOVED)//如果当前位置的 hashcode == MOVED == -1,则需要进行扩容 tab = helpTransfer(tab, f); else { V oldVal = null; synchronized (f) {//如果都不满足,则利用 synchronized 锁写入数据 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) { //如果数量大于 TREEIFY_THRESHOLD 则要转换为红黑树 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) {
//根据计算出来的 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?)
[简书博客](https://www.jianshu.com/u/835dab65e416)
公众号:代码小搬运
![代码小搬运.jpg](https://upload-images.jianshu.io/upload_images/20200230-0d78171f88c290ce.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)