ConCurrentHashMap 源码学习

ConCurrentHashMap 源码

putVal ,

//  onlyIfAbsent true -> 冲突时不替换原数据,  false -> 替换原数据
final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
		// 扰动函数,获取hash值,使key的hashcode值的高16位也参与到下标寻址的运算中
        int hash = spread(key.hashCode());
		// 为0时 表示当前node节点为null,可以直接放元素
		// 为2时,表示当前节点可能树化为红黑树节点
        int binCount = 0;
		// 自旋等待的for循环
        for (Node<K,V>[] tab = table;;) {
			// f 表示当前的头节点  n,表示为当前map的长度,i 表示当前的要放置元素的桶为下标地址,
			// fh 表示头结点的hash值
            Node<K,V> f; int n, i, fh;
			// 判断 1: 当前tab为空,表示当前tab未初始化,后续进行初始化行为
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
			 // 判断 2: 通过tabAt计算出的桶位的头结点有没有值,没有值则尝试放入
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
				// 进行插入操作,底层c++,cas原则
				// 将tab[i]桶位的值,与期望值对比,如果一致则插入 new Node<K,V>(hash, key, value, null)
				// 这里头阶段为空,期望值也为空
				// 如果插入失败,则表示当前桶为被其他线程操作,则自旋再进行其他操作逻辑
                if (casTabAt(tab, i, null,
                    new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }
			// 判断 3: 头结点不为空且当前桶位的头结点是FWD节点,正在扩容中
            else if ((fh = f.hash) == MOVED)
				// 当前线程帮助其他线程完成扩容任务
                tab = helpTransfer(tab, f);
			    // 判断 4: 当前桶位,为红黑树或者为链表
            else {
				// 当key值存在时,表示旧值value
                V oldVal = null;
				// 加锁,锁为当前桶位的头结点
                synchronized (f) {
					// 避免其他线程把头结点修改掉,如果已经修改掉,则加锁就已经错误
                    if (tabAt(tab, i) == f) {
						// 当前节点为普通链表
                        if (fh >= 0) {
							// key不冲突时为当前链表元素总个数,
							// 冲突时需要替换元素时,表示替换数据的下标位置(binCount - 1)
                            binCount = 1;
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
								// 冲突时,需要替换原位置元素,并将原value赋值并返回
                                if (e.hash == hash &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    oldVal = e.val;
									// put()时传参,为fasle替换元素,true是不替换元素
                                    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;
                                }
                            }
                        }
						// 为treeBin 代理节点
                        else if (f instanceof TreeBin) {
                            Node<K,V> p;
							//默认为2,是因为最后addCount()方法需要使用到该值,值带有不同意义
                            binCount = 2;
							//条件判断: 插入红黑树节点,没有冲突则返回null有冲突则返回冲突节点
							// 不为空是则有冲突节点存在,并将冲突节点的旧值赋值并返回
                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                           value)) != null) {
                                oldVal = p.val;
								// 参照链表此地说法
                                if (!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                    }
                }
				// 当前put元素位置为空,直接放置元素时为0,为链表或treeBin时不为0
                if (binCount != 0) {
					// 链表长度大与升级红黑树阈值,则升级为红黑树
					// 红黑树时为2不会进入该判断
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
					// 当前key与原有数据发生冲突,需要将其返回
                    if (oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
		// 统计当前散列表一共有多少数据,是否达到扩容条件
        addCount(1L, binCount);
        return null;
    }

initTable 初始化tab

    private final Node<K,V>[] initTable() {
    		// tab 当前tab引用  sc: 临时sizeCtl
            Node<K,V>[] tab; int sc;
    		// 判断是否未初始化
            while ((tab = table) == null || tab.length == 0) {
    			// 小于0(-1)表示其他线程正在初始化,是当前线程再次进入cpu竞争,把调度让给其他线程
                if ((sc = sizeCtl) < 0)
                    Thread.yield(); // lost initialization race; just spin
    			// 大于 0 未初始化时, 表示当前需要初始化的容量 , 已初始化,表示扩容的阈值
    			// 或者 等于 0  为默认容量值
    			// 上述为改if 的两种情况 , 符合则进行cas加锁,加锁成功之后,进入初始化阶段
                else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                    try {
    					// 二次判空,防止多线程情况下,其他线程已经初始化失败,重复初始化,丢失数据
                        if ((tab = table) == null || tab.length == 0) {
    						// sc 大于0 则表示初始化容量已经确定,否则则使用默认容量
                            int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                            @SuppressWarnings("unchecked")
                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                            table = tab = nt;
    						// 初始化成功将 sc设为 之后扩容的阈值
                            // n无符号右移两位,相当于把值设为原来值的 1/4,
    						// 再减去,就是(3/4)n ,相当于 n * 0.75
                            sc = n - (n >>> 2);
                        }
                    } finally {
    					// 两种情况
    					// 1 : 已经加锁成功,但是发现已经不是第一次初始化,这是应该把原有的sc设置回去
    					// 2 : 初始化成功,将sc设为扩容阈值
                        sizeCtl = sc;
                    }
                    break;
                }
            }
            return tab;
        }

addCount() 累加数据,或者扩容判断

private final void addCount(long x, int check) {
        // as ->cells 数组
        // b -> base值
        // s -> tab 中元素数量
        CounterCell[] as; long b, s;
        // cells true 数组已初始化,将数据放到cell数组内
        // false 未初始化
        if ((as = counterCells) != null ||
            // 尝试写base -> 去反后  false,写入成功,说明当前竞争不激烈,可以不用创建cell数组
            // true 写入失败,说明当前有竞争力, 需要创建cells 数组
            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
            // 成功进入的条件
            // true 数组已初始化,将数据放到cell数组内
            // true 写入失败,说明当前有竞争力, 需要创建cells 数组

            // a 寻址得到的cell 地址,
            // v 写入地址的期望值
            // m cell 数组的长度
            CounterCell a; long v; int m;
            // true 有竞争 false 无竞争
            boolean uncontended = true;
            // 数组未初始化
            if (as == null || (m = as.length - 1) < 0 ||
                // 寻址地址处元素为空
                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
                // 取反  写入base失败,发生了竞争
                !(uncontended =
                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
                // 进行后续重试或者扩容 -> 相当于 longAdder的longAccumulate()方法
                fullAddCount(x, uncontended);
                // fullAddCount()方法处理的东西较多,不参与扩容,直接返回
                return;
            }
            // binCount传入: 
            // >=1 时,hash冲突,当前位置有一个数据,或者已经成为链表 ---- 2 时 为红黑树
            // = 0 当前桶为为空,直接放入时
            // < 时 为remove操作
            if (check <= 1)
                return;
            //获取所有元素数,期望值没参与longAdder
            s = sumCount();
        }
        // 此处是put操作的一个状态
        if (check >= 0) {
            // tab 当前链表数组
            // nt 升级的数组
            // n 当前数组的长度
            // sc sizeCtl 临时值
            Node<K,V>[] tab, nt; int n, sc;
            // 数组中的元素大于阈值,原table不为null,原数组长度没超过最大值
            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
                   (n = tab.length) < MAXIMUM_CAPACITY) {
                // 获取表示符
                int rs = resizeStamp(n);
                // 小于0时,高六位表示标识符,低六位表示参与的线程数
                if (sc < 0) {
                    // 1 : 标识符是否相等,
                  //	如果扩容完毕时,表示符肯定已变更 ps: 比如 16 -> 32,32 -> 64 标识是不一样的
                    // 2 : 扩容是否结束,(表达的意思应该是 (rs << 16) + 1)
				  // 当前线程数为1 时表示,扩容已经结束,因为第一次初始化时线程 + 2,所以为1时扩容已经结束
                    // 3 : 判断是否大于最大可有线程数 (表达意思应该是 (rs << 16 + MAX_RESIZERS))
                    // 4 : 新数组为null,扩容完毕
                    // 5 : 当前区间进度 <= 0,数组扩容完毕
                    // 2,3 存在bug,不会用到
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                        transferIndex <= 0)
                        break;
                    // 尝试帮助扩容,如果cas失败,表示竞争比较多,自旋继续执行操作,
                    // 下次进来可能已经被其他线程扩容完毕
                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                        // 帮助完成库容的线程,持有nextTable
                        transfer(tab, nt);
                }
                // 大于0 表示,第一次扩容
                else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    // 第一次扩容不持有 nextTable
                    transfer(tab, null);
                s = sumCount();
            }
        }
    }

transfer(), 扩容,协助扩容方法

private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
        // n -> tab的长度
        // stride 扩容分配区间的补偿
        int n = tab.length, stride;
        // 步长计算
        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
            stride = MIN_TRANSFER_STRIDE; // subdivide range
        // 是不是第一次扩容
        if (nextTab == null) {            // initiating
            try {
                // 新创建大一倍的数组
                @SuppressWarnings("unchecked")
                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
                nextTab = nt;
            } catch (Throwable ex) {      // try to cope with OOME
                sizeCtl = Integer.MAX_VALUE;
                return;
            }
            // 赋值新表 和 扩容任务进度(当前tab长度)
            nextTable = nextTab;
            transferIndex = n;
        }
        // 新表长度
        int nextn = nextTab.length;
        // 设置新表为fwd节点
        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
        // 推进表示,true 表示还有桶位需要继续扩容
        boolean advance = true;
        // 当前步长扩容是否完成
        boolean finishing = false; // to ensure sweep before committing nextTab
        // 自旋扩容 
		//倒序分配区间 i -> 分配扩容区间起点,  n -> 扩容区间临界点   i <-> n 之间的元素为需要扩容
        for (int i = 0, bound = 0;;) {
            // f -> 头结点  fh -> 头结点 hash值
            Node<K,V> f; int fh;
            // 1: 给当前线程分配任务区间
            // 2: 维护当前线程任务进度
            // 3: 维护整个map的进度
            while (advance) {
                // 分配的   i -> 分配扩容区间起点,  n -> 扩容区间临界点
                int nextIndex, nextBoun d;
                // true 区间内还有任务未扩容完成
                if (--i >= bound || finishing)
                    advance = false;
                // 当前线程任务已完成,或未分配
                // true 全局扩容已经完成,扩容进度为0
                else if ((nextIndex = transferIndex) <= 0) {
                    // 设为-1,后续退出操作
                    i = -1;
                    advance = false;
                }
                // 当前线程需要分配任务区间,整个扩容还未完成
                // true,设置当前线程任务区间成功,如果剩余值小于步长,则把剩余项全部交给当前线程
                // false,线程较多,出现竞争
                else if (U.compareAndSwapInt
                         (this, TRANSFERINDEX, nextIndex,
                          nextBound = (nextIndex > stride ?
                                       nextIndex - stride : 0))) {
                    // 设置 起始点 和 临界点
                    bound = nextBound;
                    i = nextIndex - 1;
                    advance = false;
                }
            }
            //当前线程未分配任务
            //	后两个条件是不会成立的,因为i是原tab长度减一得到的 ,nextn是原数组的两倍
            if (i < 0 || i >= n || i + n >= nextn) {
                // 临时变量 sizeCtl
                int sc;
                // 自选之后进入,扩容已经完毕,将扩容后的数组赋值给原数组
                if (finishing) {
                    nextTable = null;
                    table = nextTab;
                    // 设为下一次扩容的阈值  (n << 1) - (n >>> 1) = n * 0.75
                    sizeCtl = (n << 1) - (n >>> 1);
                    return;
                }
                // 扩容线数 -1
                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                    // 当前线程数是不是最后一个线程
                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                        return;
                    // 如果是最后一个线程进行收尾工作  finishing标识扩容任务完毕
                    finishing = advance = true;
                    // 起始下标设为 数组长度
                    i = n; // recheck before commit
                }
            }
            // 如果当前头结点为空,讲此节点桶为设置为fwd节点
            else if ((f = tabAt(tab, i)) == null)
                advance = casTabAt(tab, i, null, fwd);
            // 当前节点为fwd节点
            else if ((fh = f.hash) == MOVED)
                advance = true; // already processed
            // 当前节点不为fwd节点,且当前节点不为空,该节点为链表或者红黑树
            else {
                // 头节点加锁
                synchronized (f) {
                    // 重复判断枷锁过程中,头结点有没有别其他线程操作修改
                    if (tabAt(tab, i) == f) {
                        // ln  低位链表  hn 高位链表
                        Node<K,V> ln, hn;
                        // >= 0 为普通node链表
                        if (fh >= 0) {
                            //此地是获取最后一串连续相同的,高位数据或者低位数据,0是低位,1是高位
                            // 然后放置到新数组的高低位置
                            int runBit = fh & n;
                            Node<K,V> lastRun = f;
                            // 循环获取连续相同的高或低位数据,组成了链表结构
                            for (Node<K,V> p = f.next; p != null; p = p.next) {
                                int b = p.hash & n;
                                if (b != runBit) {
                                    runBit = b;
                                    lastRun = p;
                                }
                            }
                            // = 0 低位链表
                            if (runBit == 0) {
                                ln = lastRun;
                                hn = null;
                            }
                            // = 1 高位链表
                            else {
                                hn = lastRun;
                                ln = null;
                            }
                            // 循环判断,除上面连续相同的高或低位数据以外的数据
                            // 并加入新的高低位链表头部,
                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
                                int ph = p.hash; K pk = p.key; V pv = p.val;
                                if ((ph & n) == 0)
                                    ln = new Node<K,V>(ph, pk, pv, ln);
                                else
                                    hn = new Node<K,V>(ph, pk, pv, hn);
                            }
                            // 写入低位链表到新tab
                            setTabAt(nextTab, i, ln);
                            // 写入低位链表到新tab
                            setTabAt(nextTab, i + n, hn);
                            // 讲旧tab  i桶位设置为fwd节点
                            setTabAt(tab, i, fwd);
                            // 继续完成后续扩容
                            advance = true;
                        }
                            // 为treeBin代理节点
                        else if (f instanceof TreeBin) {
                            // 强转为treeBin
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            // lo -> 链表  低位头节点     loTail -> 低位尾节点
                            TreeNode<K,V> lo = null, loTail = null;
                            // lo -> 链表  高位头节点     loTail -> 高位尾节点
                            TreeNode<K,V> hi = null, hiTail = null;
                            // lc,hc,计数作用,是否转为红黑树
                            int lc = 0, hc = 0;
                            // 遍历头结点
                            for (Node<K,V> e = t.first; e != null; e = e.next) {
                                int h = e.hash;
                                // 新建treeNode节点
                                TreeNode<K,V> p = new TreeNode<K,V>
                                    (h, e.key, e.val, null, null);
                                // 判断高低位
                                // 低位
                                if ((h & n) == 0) {
                                    // 上一个节点为空,将此节点作为低位链表头结点
                                    if ((p.prev = loTail) == null)
                                        lo = p;
                                    // 链表不为空,则将此节点插入到链表末尾
                                    else
                                        loTail.next = p;
                                    // 将p设为尾节点
                                    loTail = p;
                                    // 统计个数 +1
                                    ++lc;
                                }
                                // 高位  注释同上
                                else {
                                    if ((p.prev = hiTail) == null)
                                        hi = p;
                                    else
                                        hiTail.next = p;
                                    hiTail = p;
                                    ++hc;
                                }
                            }
                            // 小于6,将treeBin替换为普通node链表
                            // 大于6,将treeNode链表升级为红黑树
                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                                (hc != 0) ? new TreeBin<K,V>(lo) : t;
                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                                (lc != 0) ? new TreeBin<K,V>(hi) : t;
                            // 新表设置低位
                            setTabAt(nextTab, i, ln);
                            // 新表设置高位
                            setTabAt(nextTab, i + n, hn);
                            // 设置当前桶位位fwd节点
                            setTabAt(tab, i, fwd);
                            // 继续完成后续扩容
                            advance = true;
                        }
                    }
                }
            }
        }
    }

put时发现正在扩容要参与进来

final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
        // 新table, sizeCtl
        Node<K,V>[] nextTab; int sc;
        // tab不等于null, 改节点为fwd节点,且新table不为空
        if (tab != null && (f instanceof ForwardingNode) &&
            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
            // 扩容标识符
            int rs = resizeStamp(tab.length);
            // 多线程情况下已被扩容完成nextTable被设为null,
            // 相等说明扩容还在进行中
            // sizeCtl < 0 表示正在扩容中
            while (nextTab == nextTable && table == tab &&
                   (sc = sizeCtl) < 0) {
                // 具体看addCount()  有解说
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || transferIndex <= 0)
                    break;
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
                    transfer(tab, nextTab);
                    break;
                }
            }
            return nextTab;
        }
        return table;
    }

get()

    public V get(Object key) {
    				//tab 当前 table
    				// e 当前key命中的桶位,p 目标节点
    				// n table 长度 
    				// eh,如果当前key命中桶位不为空,则表示已存在node的hash值 ek,则表示已存在node的key值
            Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    				// 扰动hash值,更散列
            int h = spread(key.hashCode());
    				// 数组不为空并且当前桶位不为空
            if ((tab = table) != null && (n = tab.length) > 0 &&
                (e = tabAt(tab, (n - 1) & h)) != null) {
    						// 头结点hash值,key比较相等,直接命中返回
                if ((eh = e.hash) == h) {
                    if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                        return e.val;
                }
    						// 小于0,说明是fwd节点,或者为红黑树
                else if (eh < 0)
    								// find方法内寻找key值
                    return (p = e.find(h, key)) != null ? p.val : null;
    						// 尚书令两种都不符合,说明为普通链表,hash,equals比较即可
                while ((e = e.next) != null) {
                    if (e.hash == h &&
                        ((ek = e.key) == key || (ek != null && key.equals(ek))))
                        return e.val;
                }
            }
            return null;
        }

find() → fwd find

    static final class ForwardingNode<K,V> extends Node<K,V> {
            final Node<K,V>[] nextTable;
            //   创建的时候将 hash值设为 -1,将tab赋值给nextTable
            ForwardingNode(Node<K,V>[] tab) {
                super(MOVED, null, null, null);
                this.nextTable = tab;
            }
    
            Node<K,V> find(int h, Object k) {
                // loop to avoid arbitrarily deep recursion on forwarding nodes
                // 新表赋值给tab
                outer: for (Node<K,V>[] tab = nextTable;;) {
                    // e 当前元素,n tab的长度
                    Node<K,V> e; int n;
                    // 前三条件都恒不成立,最后一个表示头结点为空
                    if (k == null || tab == null || (n = tab.length) == 0 ||
                        (e = tabAt(tab, (n - 1) & h)) == null)
                        return null;


                for (;;) {
                    // 当前元素的hash
                    // 当前元素key
                    int eh; K ek;
                    // 头结点直接命中返回
                    if ((eh = e.hash) == h &&
                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                    // 可能为红黑树接口,也可能线程过多,再次进行扩容,成为fwd节点
                    if (eh < 0) {
                        if (e instanceof ForwardingNode) {
                            tab = ((ForwardingNode<K,V>)e).nextTable;
                            continue outer;
                        }
                        // 为红黑树,执行红黑树find
                        else
                            return e.find(h, k);
                    }
                    // 普通链表,自旋再次进入逻辑
                    if ((e = e.next) == null)
                        return null;
                }
            }
        }
    }

remove(), 套娃的后续方法, 在成功删除红黑树节点之后,会直接转换为node普通链表,也没有进行长度判断,正常应该为6以下转为链表

final V replaceNode(Object key, V value, Object cv) {
        // 扰动hash
        int hash = spread(key.hashCode());
        // 赋值当前table
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            // 如果当前当前tab为空,或者命中头元素为空,直接返回 删除的元素不存在
            if (tab == null || (n = tab.length) == 0 ||
                (f = tabAt(tab, i = (n - 1) & hash)) == null)
                break;
            // 如果头元素不为空,并且hash为 -1,表示当前fwd节点,需要参与扩容
            else if ((fh = f.hash) == MOVED)
                // 详看该方法
                tab = helpTransfer(tab, f);
                // 当前为链表,或者 treeBin
            else {
                // 命中的旧值
                V oldVal = null;
                boolean validated = false;
                synchronized (f) {
                    // 放置锁错对象
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            validated = true;
                            // 为普通node链表,或者node单个元素,e为循环中的node对象
                            for (Node<K,V> e = f, pred = null;;) {
                                // 当前node对象的key
                                K ek;
                                // 命中相同的key
                                if (e.hash == hash &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    // 当前节点的value
                                    V ev = e.val;
                                    // 1 : 成立则是删除操作
                                    // 2,3 : 成立时替换操作
                                    if (cv == null || cv == ev ||
                                        (ev != null && cv.equals(ev))) {
                                        // 旧值 赋值返回
                                        oldVal = ev;
                                        // 条件成立为替换操作
                                        if (value != null)
                                            e.val = value;
                                        // 删除操作,将前几点直接指向当前的节点的下一个节点
                                        // 当前节点被抛弃
                                        else if (pred != null)
                                            pred.next = e.next;
                                                // 当前为头结点,
                                        // 只需将桶节点设置为头结点的下一个节点,当前节点被抛弃
                                        else
                                            setTabAt(tab, i, e.next);
                                    }
                                    break;
                                }
                                // 当前节点设为下一轮循环元素的前一个节点
                                pred = e;
                                 // 遍历完链表最后一个为空,跳出
                                if ((e = e.next) == null)
                                    // 想要删的值不存在
                                    break;
                            }
                        }
                        // 如果是红黑树
                        else if (f instanceof TreeBin) {
                            validated = true;
                            // 强转为红黑树节点
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            // r为根节点 , p为查找到的树节点
                            TreeNode<K,V> r, p;
                            if ((r = t.root) != null &&
                                (p = r.findTreeNode(hash, key, null)) != null) {
                                // 命中需要删除或者替换的元素
                                // 命中元素的value
                                V pv = p.val;
                                // 桶链表判断
                                if (cv == null || cv == pv ||
                                    (pv != null && cv.equals(pv))) {
                                    oldVal = pv;
                                    // 此为替换操作
                                    if (value != null)
                                        p.val = value;
                                    // 此为删除操作,调用treeBin的删除逻辑
                                    else if (t.removeTreeNode(p))
                                        // 此地删除成功之后,直接转为普通node链表
                                        // 也没有进行进行元素判断
                                        setTabAt(tab, i, untreeify(t.first));
                                }
                            }
                        }
                    }
                }
                //检验表示,进入链表或者红黑树会设置为true
                if (validated) {
                    // 旧值不为空
                    if (oldVal != null) {
                          // 确定为删除操作
                        if (value == null)
                            // 总元素数 -1
                            addCount(-1L, -1);
                        // 删除替换成功之后返回旧值
                        return oldVal;
                    }
                    break;
                }
            }
        }
        return null;
    }

treeBin节点, 写是独占锁,读是共享锁

↓ treeBin节点元素含义

static final class TreeBin<K,V> extends Node<K,V> {
        // 根节点
        TreeNode<K,V> root;
        // 链表头结点
        volatile TreeNode<K,V> first;
        // 等待者线程 -> 当lockState是读锁状态时 才存在
        volatile Thread waiter;
        // 状态读写时用,写是独占锁,读是共享锁
        // 1  写线程 -> 一个treeBin只能同时存在一个读线程
        // 2  写线程时,发现当前存在读锁,当前线程是读线程,需要等待
        // 4  每来一个线程 lockState的值加4
        volatile int lockState;
        // values for lockState
        static final int WRITER = 1; // set while holding write lock
        static final int WAITER = 2; // set when waiting for write lock
        static final int READER = 4; // increment value for setting read lock
}

创建treeBin对象

TreeBin(TreeNode<K,V> b) {
            // 设置hash为-2,红黑树节点,  -1 为fwd节点
            super(TREEBIN, null, null, null);
            // 头结点为当前引用节点
            this.first = b;
            // r 红黑树根节点
            TreeNode<K,V> r = null;
            // 自旋插入所有node链表数据
            for (TreeNode<K,V> x = b, next; x != null; x = next) {
                // 下一个node元素
                next = (TreeNode<K,V>)x.next;
                // 插入红黑树,左右节点设空
                x.left = x.right = null;
                // 第一次进,根节点,把头结点设为红黑树根节点
                if (r == null) {
                    // 跟节点无父节点
                    x.parent = null;
                       // 根节点为黑
                    x.red = false;
                    // 赋值给根节点
                    r = x;
                }
                else {
                    // 根节点已存在
                    // 当前节点的key
                    K k = x.key;
                    // 当前节点的hash
                    int h = x.hash;
                    // 当前节点的类
                    Class<?> kc = null;
                    // 自旋,存在自己点
                    for (TreeNode<K,V> p = r;;) {
                        // dir 表示  -1 当前节点的左节点, 1 当前节点的右节点
                        // ph,当前红黑树引用节点的hash值
                        int dir, ph;
                        // 当前红黑树节点的 key
                        K pk = p.key;
                        // 当前红黑树节点 大于 插入node节点的hash值,分配到该节点左边
                        if ((ph = p.hash) > h)
                            dir = -1;
                        // 当前红黑树节点 小于 插入node节点的hash值,分配到该节点右边
                        else if (ph < h)
                            dir = 1;
                        // 如果hash值相等,则判断类是否为空
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)
                            // 此地会最终判断大小 , 赋值为 -1 或 1
                            dir = tieBreakOrder(k, pk);
                            // 当前红黑树节点设置为父节点
                            TreeNode<K,V> xp = p;
                            // 如果不等于null 说明存在子节点,继续自旋遍历
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                            // 进来之后说明要插入的子节点位置为空
                            // 设置插入节点的父节点
                            x.parent = xp;
                            // 根据表示判断插入左右位置
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            // 插入后可能影响红黑树平衡,该方法进行平衡操作,并返回最终平衡树
                            r = balanceInsertion(r, x);
                            break;
                        }
                    }
                }
            }
            // 设置根节点
            this.root = r;
            assert checkInvariants(root);
        }

find() get值的时候用到

final Node<K,V> find(int h, Object k) {
            // key不为空
            if (k != null) {
                    // 循环的当前元素
	               for (Node<K,V> e = first; e != null; ) {
                    // s lockState的状态,读写区分
                    // ek 当前节点key值
                    int s; K ek;
                    // 存在线程读,将本身加入,lockState +4,
                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
                        // 判断hash,key值相等,直接返回
                        if (e.hash == h &&
                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
                            return e;
                            // 自旋下一个循环
                        e = e.next;
                    }
                    // 当红黑树,无其他线程操作
                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
                                                 s + READER)) {
                        // r 跟节点引用
                        // 根据key值查询出的节点
                        TreeNode<K,V> r, p;
                        try {
                            // findTreeNode() 从红黑树内查询
                            p = ((r = root) == null ? null :
                                 r.findTreeNode(h, k, null));
                        } finally {
                            Thread w;
                            // U.getAndAddInt(this, LOCKSTATE, -READER)
                            //当前线程读红黑树结束   线程退出 -4
                            // READER|WAITER = 0110 = 表示一个线程在读,一个线程在等待
                            // 且当前线程是读线程的最后一个线程
                            // w = waiter 有一个写线程在等待读线程结束
                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
                                (READER|WAITER) && (w = waiter) != null)
                                //读线程全部完毕,把等待的写线程放开
                                LockSupport.unpark(w);
                        }
                        return p;
                    }
                }
            }
            return null;
        }

putTreeVal

final TreeNode<K,V> putTreeVal(int h, K k, V v) {
            // 这里是判断新节点放在什么位置 treeBin构造方法有写

            Class<?> kc = null;
            boolean searched = false;
            for (TreeNode<K,V> p = root;;) {
                int dir, ph; K pk;
                if (p == null) {
                    first = root = new TreeNode<K,V>(h, k, v, null, null);
                    break;
                }
                else if ((ph = p.hash) > h)
                    dir = -1;
                else if (ph < h)
                    dir = 1;
                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                    return p;
                else if ((kc == null &&
                          (kc = comparableClassFor(k)) == null) ||
                         (dir = compareComparables(kc, k, pk)) == 0) {
                    if (!searched) {
                        TreeNode<K,V> q, ch;
                        searched = true;
                        if (((ch = p.left) != null &&
                             (q = ch.findTreeNode(h, k, kc)) != null) ||
                            ((ch = p.right) != null &&
                             (q = ch.findTreeNode(h, k, kc)) != null))
                            return q;
                    }
                    dir = tieBreakOrder(k, pk);
                }

                // 当前节点,赋予插入节点的前一个节点
                TreeNode<K,V> xp = p;
                // 判断插入节点是否为空,不为空继续自旋向下查找
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    // x 需要插入的节点,f 旧的头结点
                    TreeNode<K,V> x, f = first;
                    // 设为链表新的头结点
                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
                    // 将旧的头结点,设为当前需要插入的新元素
                    if (f != null)
                        f.prev = x;
                    // 插入父节点的位置
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    // 是否黑色,如果是直接插入红色节点
                    if (!xp.red)
                        x.red = true;
                    else {
                        // 当前插入的父节点为红色,红红相连,需要调整平衡
                        lockRoot();
                        // 如果线程被挂起,则在读操作完毕之后,回复写线程到此处,继续执行
                        try {
                            root = balanceInsertion(root, x);
                        } finally {
                            unlockRoot();
                        }
                    }
                    break;
                }
            }
            assert checkInvariants(root);
            return null;

lockRoot() ,unlockRoot() 调整红黑树时加锁解锁

private final void lockRoot() {
            // true 说明当前存在读锁,或者等待线程
            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
                // 竞争锁
                contendedLock(); // offload to separate method
        }

        /**
         * Releases write lock for tree restructuring.
         */
        // 释放锁
        private final void unlockRoot() {
            lockState = 0;
        }

        /**
         * Possibly blocks awaiting root lock.
         */
        private final void contendedLock() {
						//  
            boolean waiting = false;
            for (int s;;) {
                // 取反 ~WAITER => 1111 ... 1101  
                // (s = lockState) & ~WAITER) == 0 
                // true 表示当前没有读线程
                if (((s = lockState) & ~WAITER) == 0) {
                    // 设置写写线程  true 抢占锁成功
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
                        // 设置treeBin waiter为null
                        if (waiting)
                            waiter = null;
                        return;
                    }
                }
                // WAITER 0010
                // 当前标志为 0 ,可以设置加锁设置写线程
                else if ((s & WAITER) == 0) {
                    // 设置treeBin 表示 lockState 为1  -> 写线程
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
                     // 写线程设置成功,将此线程赋值为写线程
                        waiting = true;
                        waiter = Thread.currentThread();
                    }
                }
                // 挂起此线程
                else if (waiting)
                    LockSupport.park(this);
            }
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值