/** Implementation for put and putIfAbsent * 实现put和putIfAbsent * onlyIfAbsent含义:如果我们传入的key已存在我们是否去替换,true:不替换,false:替换。 * */ final V putVal(K key, V value, boolean onlyIfAbsent) { //键值都不为空 if (key == null || value == null) thrownewNullPointerException(); //发散键的hash值 inthash= spread(key.hashCode()); //桶数量 0 intbinCount=0; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; //检查表是否初始化 if (tab == null || (n = tab.length) == 0) //初始化表 tab = initTable(); //检查指定键所在节点是否为空 elseif ((f = tabAt(tab, i = (n - 1) & hash)) == null) { //通过CAS方法添加键值对 if (casTabAt(tab, i, null, newNode<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin 添加到空桶时没有锁 } //如果当前节点的Hash值为MOVED elseif ((fh = f.hash) == MOVED) //如果还在进行扩容操作就先进行扩容 tab = helpTransfer(tab, f); else { VoldVal=null; //synchronized锁定此f节点 synchronized (f) { //再次检测节点是否相同 if (tabAt(tab, i) == f) { //如果此节点hash值大于0 if (fh >= 0) { //桶数量为1 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; //onlyIfAbsent:如果我们传入的key已存在我们是否去替换,true:不替换,false:替换。 if (!onlyIfAbsent) //替换掉 e.val = value; break; } Node<K,V> pred = e; //下一个节点为空 if ((e = e.next) == null) { //新建节点 pred.next = newNode<K,V>(hash, key, value, null); break; } } } //如果时树节点 elseif (f instanceof TreeBin) { Node<K,V> p; //桶数量为2 binCount = 2; //找到插入的位置,插入节点,平衡插入 if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } //如果桶数量不为0 if (binCount != 0) { //如果桶数量大于树化阈值 if (binCount >= TREEIFY_THRESHOLD) //将链表转为树 treeifyBin(tab, i); //如果老的值存在,则返回 if (oldVal != null) return oldVal; break; } } } //增加数量 addCount(1L, binCount); returnnull; }
这个方法的大概思路就是:
初始化操作
如果待插入键的插入位置没有节点,则通过CAS方式创建一个节点。
如果当前节点的Hash值为 static final int MOVED = -1; // hash for forwarding nodes 转发节点的哈希,则调用helpTransfer方法,如果还在进行扩容操作就先进行扩容,Helps transfer if a resize is in progress。