对当前容量大小进行检查,如果超过了临界值(实际大小*加载因子)就进行扩容
final V putVal(K key, V value, boolean onlyIfAbsent) { // key 和 value 均不允许为 null if (key == null || value == null) throw new NullPointerException(); // 根据 key 计算出 hash 值 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(); // f 即为当前 key 定位出的 Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,失败则自旋保证成功 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin } // 如果当前位置的 hashcode == MOVED == -1,则需要进行扩容 else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); // 如果都不满足,则利用 synchronized 锁写入数据 else { // 剩下情况又分两种,插入链表、插入红黑树 V oldVal = null; //采用同步内置锁实现并发控制 synchronized (f) { if (tabAt(tab, i) == f) { // 如果 fh=f.hash >=0,当前为链表,在链表中插入新的键值对 if (fh >= 0) { binCount = 1; //遍历链表,如果找到对应的 node 节点,修改 value,否则直接在链表尾部加入节点 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) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } // 对当前容量大小进行检查,如果超过了临界值(实际大小*加载因子)就需要扩容 addCount(1L, binCount); return null; }Java集合面试题汇总篇 (10)
内容版权声明:除非注明,否则皆为本站原创文章。