8 ConcurrentHashMap 源码注释2

/**
     * 如果指定的值key还没有关联到一个value,那么尝试使用给定的函数计算它的值,
     * 如果值不为null,则将它放入此map中
     * If the specified key is not already associated with a value,
     * attempts to compute its value using the given mapping function
     * and enters it into this map unless {@code null}.  The entire
     * 整个方法调用是原子执行的,因此这个函数每个key最多使用一次。
     * method invocation is performed atomically, so the function is
     * applied at most once per key.  Some attempted update operations
     * 在计算过程中可能会阻止其他线程对该map进行的某些尝试更新操作,因此计算应该简短并且简单,
     * 不得尝试更新此map的任何其他映射。
     * on this map by other threads may be blocked while computation
     * is in progress, so the computation should be short and simple,
     * and must not attempt to update any other mappings of this map.
     *
     * @param key key with which the specified value is to be associated
     * @param mappingFunction the function to compute a value
     * @return the current (existing or computed) value associated with
     *         the specified key, or null if the computed value is null
     * @throws NullPointerException if the specified key or mappingFunction
     *         is null
     * @throws IllegalStateException if the computation detectably
     *         attempts a recursive update to this map that would
     *         otherwise never complete
     * @throws RuntimeException or Error if the mappingFunction does so,
     *         in which case the mapping is left unestablished
     */
    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
        // 判空
        if (key == null || mappingFunction == null)
            throw new NullPointerException();

        // 计算key 的哈希值
        int h = spread(key.hashCode());
        V val = null;
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                // 如果table还没初始化,那么初始化table
                tab = initTable();

            // 如果key 对应的索引位置上还没有元素
            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
                // todo : 为什么不使用CAS把值放入
                //  -->不直接使用CAS把目标node放入的原因是:使用给定函数计算目标值可能是一个比较耗时的过程,一旦发现该
                //     索引位置上没有元素,那么先创建一个ReservationNode,并使用它作为该索引位置的锁,然后获取锁,再使
                //     用CAS设置进去,占住该索引位置,然后再利用给定的函数,计算其值,计算完成了再创建目标node,然后替换
                //     为目标node。否则CAS失败了还得判断是否存在这个元素,然后继续处理
                Node<K,V> r = new ReservationNode<K,V>();

                // 先获取锁,再使用CAS设置值,避免CAS成功后,被其他线程先获取到了锁
                synchronized (r) {
                    if (casTabAt(tab, i, null, r)) {
                        // CAS成功后,binCount值设置为1
                        binCount = 1;
                        Node<K,V> node = null;
                        try {
                            // 使用给定的函数计算值,参数传入key
                            if ((val = mappingFunction.apply(key)) != null)
                                node = new Node<K,V>(h, key, val, null);

                            // 如果计算的值为null,那么什么都不做
                        } finally {
                            // 1、如果异常了,那么会把该索引位置上的值设置回null
                            // 2、如果没有异常,那么会把该索引位置上的值设置为目标node
                            // ReservationNode 会被覆盖掉
                            setTabAt(tab, i, node);
                        }
                    }
                }
                // binCount != 0,说明数据插入完成了,也可能值为null,没有进行插入,
                // 如果是计算出现异常,那么线程不会执行到这里,上面就抛出异常了
                if (binCount != 0)
                    break;
            }

            // 如果当前正在进行扩容,那么先帮忙搬运数据
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);

            else {
                boolean added = false;
                // 先获取锁
                synchronized (f) {
                    // 获取到锁后还需要判断,该索引位置的第一个元素是否还是f
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek; V ev;
                                if (e.hash == h &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    // key 已存在,获取key 映射的值
                                    val = e.val;
                                    break;  // 结束循环
                                }
                                Node<K,V> pred = e;
                                // e = e.next, e.next = null说明该索引位置上没有其他元素了
                                if ((e = e.next) == null) {
                                    // 使用给定的函数计算值,参数传入key
                                    if ((val = mappingFunction.apply(key)) != null) {
                                        added = true;
                                        // 插入数据
                                        pred.next = new Node<K,V>(h, key, val, null);
                                    }
                                    // 如果计算的值为null,那么什么都不做

                                    // break 退出循环,binCount不会再自增
                                    break;
                                }
                            }
                        }
                        else if (f instanceof TreeBin) {
                            // binCount 设置为2,当存在竞争的时候可以进行扩容,当存在多线程竞争的时候 binCount <= 1,不会
                            // 进行扩容
                            binCount = 2;
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            TreeNode<K,V> r, p;
                            // findTreeNode()查找key对应的节点,没有返回null
                            // 如果 p != null,说明key 已经存在
                            if ((r = t.root) != null &&
                                (p = r.findTreeNode(h, key, null)) != null)
                                // 获取key 映射的值
                                val = p.val;
                            // 如果key不存在,使用给定的函数计算值,参数传入key
                            else if ((val = mappingFunction.apply(key)) != null) {
                                added = true;
                                t.putTreeVal(h, key, val);
                            }
                        }
                    }
                }
                // 如果该索引位置在插入之前已有元素,那么binCount 一定不为0,但是 tabAt(tab, i) == f值为false的
                // 时候binCount的值为0,而added的值是false,所以这里必须要判断 binCount != 0
                if (binCount != 0) {
                    // TREEIFY_THRESHOLD = 8。 binCount不包含新插入的元素,因此加上新插入的元素,slot中元素个数达到
                    // 9个才会转成红黑树。HashMap的computeIfAbsent()元素个数达到8个就转成红黑树
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    // added = false 说明key在之前已经存在,直接返回原来的值,元素个数不需要 +1
                    if (!added)
                        return val;
                    break;
                }
            }
        }

        if (val != null)
            // 元素个数 + 1
            addCount(1L, binCount);

        // 返回原来的值/新的值
        return val;
    }

    /**
     * If the value for the specified key is present, attempts to
     * compute a new mapping given the key and its current mapped
     * value.  The entire method invocation is performed atomically.
     * Some attempted update operations on this map by other threads
     * may be blocked while computation is in progress, so the
     * computation should be short and simple, and must not attempt to
     * update any other mappings of this map.
     *
     * @param key key with which a value may be associated
     * @param remappingFunction the function to compute a value
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException if the specified key or remappingFunction
     *         is null
     * @throws IllegalStateException if the computation detectably
     *         attempts a recursive update to this map that would
     *         otherwise never complete
     * @throws RuntimeException or Error if the remappingFunction does so,
     *         in which case the mapping is unchanged
     */
    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        // 判空
        if (key == null || remappingFunction == null)
            throw new NullPointerException();
        // 计算key 的hash值
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                // 如果table还没初始化,那么初始化table
                tab = initTable();

            // 如果该索引位置上还没有元素,那么结束循环
            else if ((f = tabAt(tab, i = (n - 1) & h)) == null)
                break;

                // 如果当前正在进行扩容,那么先帮忙搬运数据
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);

            else {
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f, pred = null;; ++binCount) {
                                K ek;
                                if (e.hash == h &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    // 找到key 所在的节点,使用给定的函数计算值,参数传入 key,原来的值
                                    val = remappingFunction.apply(key, e.val);

                                    if (val != null)
                                        // 如果值不为null,替换原来的值
                                        e.val = val;
                                    else {
                                        // 如果计算出新的值为null,那么删除这个节点
                                        delta = -1;
                                        // Node 只有next,没有prev
                                        Node<K,V> en = e.next;
                                        if (pred != null)
                                            // pred.next 指向删除节点的下一个节点
                                            pred.next = en;
                                        else
                                            // 如果删除的节点是该索引位置上的第一个节点,那么修改
                                            // 第一个节点为: e.next
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;

                                // 该索引位置上没有下一个元素了,break
                                if ((e = e.next) == null)
                                    break;
                            }
                        }
                        else if (f instanceof TreeBin) {
                            // binCount 设置为2,当存在竞争的时候可以进行扩容,当存在多线程竞争的时候 binCount <= 1,不会
                            // 进行扩容。 在这里的主要作用就是下面的判断: if (binCount != 0)  break;
                            binCount = 2;
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            TreeNode<K,V> r, p;
                            if ((r = t.root) != null &&
                                (p = r.findTreeNode(h, key, null)) != null) {
                                // p != null 说明 key已存在此map中

                                // 使用给定的函数计算新的值,参数传入 key,原来的值
                                // 这里把原来的值传进去了,因此可以很容易地实现在原来的值上做加减
                                val = remappingFunction.apply(key, p.val);

                                if (val != null)
                                    // 如果新的值不为null,那么替换原来的值
                                    p.val = val;
                                else {
                                    // 如果新的值为null,那么删除此节点
                                    delta = -1;
                                    // removeTreeNode()如果删除后红黑树的结构太小,如果返回true,表示需要把红黑树转成链表
                                    if (t.removeTreeNode(p))
                                        setTabAt(tab, i, untreeify(t.first));
                                }
                            }
                        }
                    }
                }
                if (binCount != 0)
                    break;
            }
        }

        // delta = -1,说明新的值为null,那么会把key所在的节点删除,因此元素个数 -1
        if (delta != 0)
            addCount((long)delta, binCount);
        // 返回新的值
        return val;
    }

    /**
     * Attempts to compute a mapping for the specified key and its
     * current mapped value (or {@code null} if there is no current
     * mapping). The entire method invocation is performed atomically.
     * Some attempted update operations on this map by other threads
     * may be blocked while computation is in progress, so the
     * computation should be short and simple, and must not attempt to
     * update any other mappings of this Map.
     *
     * @param key key with which the specified value is to be associated
     * @param remappingFunction the function to compute a value
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException if the specified key or remappingFunction
     *         is null
     * @throws IllegalStateException if the computation detectably
     *         attempts a recursive update to this map that would
     *         otherwise never complete
     * @throws RuntimeException or Error if the remappingFunction does so,
     *         in which case the mapping is unchanged
     */
    // 如果key 存在,新的值不为null,那么更新key映射的值为新的值,如果新的值为null,那么删除此节点;
    // 如果key 不存在,新的值不为null,那么进行插入,如果新的值为null,那么什么都不做
    public V compute(K key,
                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        // 判空
        if (key == null || remappingFunction == null)
            throw new NullPointerException();
        // 计算key 的hash值
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                // 如果table还没初始化,那么初始化table
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
                // 如果该索引位置上还没有元素,那么创建一个ReservationNode,把该索引位置占住
                Node<K,V> r = new ReservationNode<K,V>();
                // 先获取锁,再使用CAS设置值,避免CAS成功后,被其他线程先获取到了锁
                synchronized (r) {
                    if (casTabAt(tab, i, null, r)) {
                        binCount = 1;
                        Node<K,V> node = null;
                        try {
                            // 使用给定的函数计算
                            if ((val = remappingFunction.apply(key, null)) != null) {
                                // 如果计算的值不为null,那么插入到map中
                                delta = 1;
                                node = new Node<K,V>(h, key, val, null);
                            }

                            // 如果计算的值为null,那么什么都不做
                        } finally {
                            // 1、如果异常了或者新的值为null,那么会把该索引位置上的值设置回null
                            // 2、如果没有异常,那么会把该索引位置上的值设置为目标node
                            // ReservationNode 会被覆盖掉
                            setTabAt(tab, i, node);
                        }
                    }
                }
                // binCount != 0,说明数据插入完成了,也可能值为null,没有进行插入,
                // 如果是计算出现异常,那么线程不会执行到这里,上面就抛出异常了
                if (binCount != 0)
                    break;
            }

            // 如果当前正在进行扩容,那么先帮忙搬运数据
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);

            else {
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f, pred = null;; ++binCount) {
                                K ek;
                                if (e.hash == h &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    // 找到key 所在的节点,使用给定的函数计算值,参数传入 key,原来的值
                                    val = remappingFunction.apply(key, e.val);

                                    if (val != null)
                                        // 如果值不为null,替换原来的值
                                        e.val = val;
                                    else {
                                        // 如果计算出新的值为null,那么删除这个节点
                                        delta = -1;
                                        Node<K,V> en = e.next;
                                        if (pred != null)
                                            // pred.next 指向删除节点的下一个节点
                                            pred.next = en;
                                        else
                                            // 如果删除的节点是该索引位置上的第一个节点,那么修改
                                            // 第一个节点为: e.next
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;

                                // 该索引位置上没有其他元素了,说明key在此map中不存在,进行插入处理
                                if ((e = e.next) == null) {
                                    // 使用给定的函数计算值,参数传入key,null
                                    val = remappingFunction.apply(key, null);
                                    if (val != null) {
                                        delta = 1;
                                        // 插入数据
                                        pred.next =
                                            new Node<K,V>(h, key, val, null);
                                    }
                                    // 如果计算的值为null,那么什么都不做

                                    break;
                                }
                            }
                        }
                        else if (f instanceof TreeBin) {
                            // binCount 设置为2,当存在竞争的时候可以进行扩容,当存在多线程竞争的时候 binCount <= 1,不会
                            // 进行扩容
                            binCount = 1;
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            TreeNode<K,V> r, p;
                            if ((r = t.root) != null)
                                // findTreeNode()查找key对应的节点,没有返回null
                                p = r.findTreeNode(h, key, null);
                            else
                                // root = null,p 没有初始化,所以初始化为null (不会存在root = null的情况)
                                p = null;
                            V pv = (p == null) ? null : p.val;
                            // 使用给定的函数计算值,参数传入key, pv
                            val = remappingFunction.apply(key, pv);
                            if (val != null) {
                                // p != null,说明key已存在
                                if (p != null)
                                    // 使用新的值替换原来的值
                                    p.val = val;
                                else {
                                    // 插入数据
                                    delta = 1;
                                    t.putTreeVal(h, key, val);
                                }
                            }

                            // 新的值 val = null
                            else if (p != null) {
                                // p != null,而新的值为null,所以删除此节点
                                delta = -1;
                                // removeTreeNode()如果删除后红黑树的结构太小,如果返回true,表示需要把红黑树转成链表
                                if (t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                }
                if (binCount != 0) {
                    // TREEIFY_THRESHOLD = 8。 binCount不包含新插入的元素,因此加上新插入的元素,slot中元素个数达到
                    // 9个才会转成红黑树
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    break;
                }
            }
        }

        // 更新元素个数
        if (delta != 0)
            addCount((long)delta, binCount);
        return val;
    }

    /**
     * If the specified key is not already associated with a
     * (non-null) value, associates it with the given value.
     * Otherwise, replaces the value with the results of the given
     * remapping function, or removes if {@code null}. The entire
     * method invocation is performed atomically.  Some attempted
     * update operations on this map by other threads may be blocked
     * while computation is in progress, so the computation should be
     * short and simple, and must not attempt to update any other
     * mappings of this Map.
     *
     * @param key key with which the specified value is to be associated
     * @param value the value to use if absent
     * @param remappingFunction the function to recompute a value if present
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException if the specified key or the
     *         remappingFunction is null
     * @throws RuntimeException or Error if the remappingFunction does so,
     *         in which case the mapping is unchanged
     */
    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        // key 和 value 都不能为null,否则抛出NullPointerException
        if (key == null || value == null || remappingFunction == null)
            throw new NullPointerException();
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        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) & h)) == null) {
                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
                    delta = 1;
                    val = value;
                    break;
                }
            }
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else {
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f, pred = null;; ++binCount) {
                                K ek;
                                if (e.hash == h &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    val = remappingFunction.apply(e.val, value);
                                    if (val != null)
                                        e.val = val;
                                    else {
                                        delta = -1;
                                        Node<K,V> en = e.next;
                                        if (pred != null)
                                            pred.next = en;
                                        else
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;
                                if ((e = e.next) == null) {
                                    delta = 1;
                                    val = value;
                                    pred.next =
                                        new Node<K,V>(h, key, val, null);
                                    break;
                                }
                            }
                        }
                        else if (f instanceof TreeBin) {
                            binCount = 2;
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            TreeNode<K,V> r = t.root;
                            TreeNode<K,V> p = (r == null) ? null :
                                r.findTreeNode(h, key, null);
                            val = (p == null) ? value :
                                remappingFunction.apply(p.val, value);
                            if (val != null) {
                                if (p != null)
                                    p.val = val;
                                else {
                                    delta = 1;
                                    t.putTreeVal(h, key, val);
                                }
                            }
                            else if (p != null) {
                                delta = -1;
                                if (t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                }
                if (binCount != 0) {
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    break;
                }
            }
        }
        if (delta != 0)
            addCount((long)delta, binCount);
        return val;
    }

    // Hashtable legacy methods

    /**
     * Legacy method testing if some key maps into the specified value
     * in this table.  This method is identical in functionality to
     * {@link #containsValue(Object)}, and exists solely to ensure
     * full compatibility with class {@link java.util.Hashtable},
     * which supported this method prior to introduction of the
     * Java Collections framework.
     *
     * @param  value a value to search for
     * @return {@code true} if and only if some key maps to the
     *         {@code value} argument in this table as
     *         determined by the {@code equals} method;
     *         {@code false} otherwise
     * @throws NullPointerException if the specified value is null
     */
    public boolean contains(Object value) {
        return containsValue(value);
    }

    /**
     * Returns an enumeration of the keys in this table.
     *
     * @return an enumeration of the keys in this table
     * @see #keySet()
     */
    public Enumeration<K> keys() {
        Node<K,V>[] t;
        int f = (t = table) == null ? 0 : t.length;
        return new KeyIterator<K,V>(t, f, 0, f, this);
    }

    /**
     * Returns an enumeration of the values in this table.
     *
     * @return an enumeration of the values in this table
     * @see #values()
     */
    public Enumeration<V> elements() {
        Node<K,V>[] t;
        int f = (t = table) == null ? 0 : t.length;
        return new ValueIterator<K,V>(t, f, 0, f, this);
    }

    // ConcurrentHashMap-only methods

    /**
     * 返回映射的数量。应该使用此方法代替size(),因为ConcurrentHashMap可能
     * 包含比可以表示为int的更多映射。
     * Returns the number of mappings. This method should be used
     * instead of {@link #size} because a ConcurrentHashMap may
     * contain more mappings than can be represented as an int. The
     *  返回的值是估计值; 如果并发插入或移除,实际计数可能会有所不同。
     * value returned is an estimate; the actual count may differ if
     * there are concurrent insertions or removals.
     *
     * @return the number of mappings
     * @since 1.8
     */
    public long mappingCount() {
        long n = sumCount();
        // 忽略瞬时的负值
        return (n < 0L) ? 0L : n; // ignore transient negative values
    }

    /**
     * 创建一个新的Set,由一个ConcurrentHashMap支持,使用给定的类型Boolean.TRUE 。
     * Creates a new {@link Set} backed by a ConcurrentHashMap
     * from the given type to {@code Boolean.TRUE}.
     *
     * @param <K> the element type of the returned set
     * @return the new set
     * @since 1.8
     */
    // 这是一个静态方法,新创建一个由ConcurrentHashMap支持的Set集合
    public static <K> KeySetView<K,Boolean> newKeySet() {
        return new KeySetView<K,Boolean>
            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
    }

    /**
     * Creates a new {@link Set} backed by a ConcurrentHashMap
     * from the given type to {@code Boolean.TRUE}.
     *
     * @param initialCapacity The implementation performs internal
     * sizing to accommodate this many elements.
     * @param <K> the element type of the returned set
     * @return the new set
     * @throws IllegalArgumentException if the initial capacity of
     * elements is negative
     * @since 1.8
     */
    // 静态方法,新创建一个由 能容纳指定元素数量的ConcurrentHashMap支持的Set集合
    // initialCapacity 是 table 可容纳的元素个数,而不是 table 的 size
    public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
        return new KeySetView<K,Boolean>
            (new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
    }

    /**
     * 返回这个map中的keys的set视图,对于任何的添加( add()、addAll() )使用
     * 给定的公共映射值。
     * Returns a {@link Set} view of the keys in this map, using the
     * given common mapped value for any additions (i.e., {@link
     * Collection#add} and {@link Collection#addAll(Collection)}).
     * 当然,这只适用于从这个视图中对所有添加使用相同的值是可接受的
     * This is of course only appropriate if it is acceptable to use
     * the same value for all additions from this view.
     *
     * @param mappedValue the mapped value to use for any additions
     * @return the set view
     * @throws NullPointerException if the mappedValue is null
     */
    // 此方法返回的set支持插入元素
    public KeySetView<K,V> keySet(V mappedValue) {
        // mappedValue 不能为null
        if (mappedValue == null)
            throw new NullPointerException();
        return new KeySetView<K,V>(this, mappedValue);
    }

    /* ---------------- Special Nodes -------------- */

    /**
     * A node inserted at head of bins during transfer operations.
     */
    static final class ForwardingNode<K,V> extends Node<K,V> {

        // 扩容新的table
        final Node<K,V>[] nextTable;

        // tab -> 扩容时使用的新table
        ForwardingNode(Node<K,V>[] tab) {
            // hash值为 MOVED
            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
            outer: for (Node<K,V>[] tab = nextTable;;) {
                // tab = nextTable    n = nextTable的长度
                Node<K,V> e; int n;
                // 1、key = null  2、nextTable 为null 或者没有元素  3、key对应的索引位置上没有元素
                // 这三种情况直接返回null
                if (k == null || tab == null || (n = tab.length) == 0 ||
                    (e = tabAt(tab, (n - 1) & h)) == null)
                    return null;

                for (;;) {
                    int eh; K ek;
                    if ((eh = e.hash) == h &&
                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        // 找到,返回
                        return e;
                    if (eh < 0) {
                        // 如果 e 是 ForwardingNode 类型的,说明元素查找过程中table又一次扩容了,从新的表中去查找
                        if (e instanceof ForwardingNode) {
                            tab = ((ForwardingNode<K,V>)e).nextTable;
                            // 跳到外部循环
                            continue outer;
                        }
                        else
                            // e 可能是 TreeBin节点,也有可能是 ReservationNode节点,使用相应的子类方法去查找
                            return e.find(h, k);
                    }
                    // e = e.next 往下遍历
                    if ((e = e.next) == null)
                        return null;
                }
            }
        }
    }

    /**
     * 在computeIfAbsent和compute中使用的位置保持节点
     * A place-holder node used in computeIfAbsent and compute
     */
    static final class ReservationNode<K,V> extends Node<K,V> {
        ReservationNode() {
            // RESERVED  = -3
            super(RESERVED, null, null, null);
        }

        // 直接返回 null
        Node<K,V> find(int h, Object k) {
            return null;
        }
    }

    /* ---------------- Table Initialization and Resizing -------------- */

    /**
     * Returns the stamp bits for resizing a table of size n.
     * 当通过RESIZE_STAMP_SHIFT左移时,必须为负。
     * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
     */
    // n = table.length
    static final int resizeStamp(int n) {
        // numberOfLeadingZeros()返回最高位的1的左边的0的个数
        // RESIZE_STAMP_BITS = 16
        // 1 << (RESIZE_STAMP_BITS - 1) ->  1000 0000 0000 0000 0000
        // ->   | (1 << (RESIZE_STAMP_BITS - 1)) 的目的是,生成的值向左移动16位后的数一定是负数
        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
    }

    /**
     * 使用sizeCtl中记录的size初始化表。
     * Initializes table, using the size recorded in sizeCtl.
     */
    private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        while ((tab = table) == null || tab.length == 0) {
            // 把 sizeCtl 赋值先赋值给 sc,因为下面会先修改 sizeCtl的值
            if ((sc = sizeCtl) < 0)
                // 初始化竞争失败,仅仅自旋
                Thread.yield(); // lost initialization race; just spin

            // CAS设置 sizeCtl值为 -1,成功才能对 table进行初始化
            // sizeCtl 使用volatile修饰
            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                    // 若两个线程同时进入了 while()块里面,第一个线程完成初始化并重新设置sizeCtl后,
                    // 第二个线程就有可能进入到这里,所以还需要判断 table是否已经初始化了
                    if ((tab = table) == null || tab.length == 0) {
                        // 若sc = 0 表示没有指定table初始化的size,因此将会使用默认的size, DEFAULT_CAPACITY = 16
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        // 初始化 table
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = tab = nt;
                        // sc = n - (1/4)n = 0.75 * n;
                        sc = n - (n >>> 2);
                    }
                } finally {
                    // 修改sizeCtl的值,不需要使用CAS,因此此时相当于获取到了锁
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }

    /**
     * 添加到count,如果表太小且还没有调整大小,则启动transfer
     * Adds to count, and if table is too small and not already
     * resizing, initiates transfer. If already resizing, helps
     * perform transfer if work is available.
     * 在转移后重新检查占用情况,看看是否已经需要另一个大小调整,因为大小调整是滞后的添加。
     * Rechecks occupancy
     * after a transfer to see if another resize is already needed
     * because resizings are lagging additions.
     *
     * @param x the count to add
     * @param check if <0, don't check resize, if <= 1 only check if uncontended
     */
    private final void addCount(long x, int check) {
        CounterCell[] as; long b, s;

        // 一旦 counterCells != null, 就不会再修改 baseCount的值
        if ((as = counterCells) != null ||
                // 使用CAS修改 baseCount的值,在原来的值上 +x.        s = b + x
            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {

            // ---   counterCells != null || CAS更新 baseCount 失败    ----

            CounterCell a; long v; int m;
            boolean uncontended = true;

            // ------      ConcurrentHashMap 并不是元素个数达到 sizeCtl就会进行扩容  -----------

            // 1、as == null || (m = as.length - 1) < 0 说明 counterCells还没有初始化
            // 2、(a = as[ThreadLocalRandom.getProbe() & m]) == null 该线程对应的counterCells上的元素为null
            // 3、CAS更新 counterCell上的数据失败
            if (as == null || (m = as.length - 1) < 0 ||
                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
                !(uncontended =
                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {

                // 计数值 + x
                fullAddCount(x, uncontended);
                // 以上所述的3种情况,完成计数相加之后,方法直接返回,不会进行扩容
                return;
            }

            // CAS 修改相应的counterCell 上的值成功之后,判断check的值,小于等于1直接返回,不会进行扩容,也就是该 slot上的
            // 元素个数,在插入之前至少应该有两个 (加上新插入的元素至少有3个) 才会去判断是否进行扩容
            if (check <= 1)
                return;

            // 统计元素个数
            s = sumCount();
        }

        // check >= 0 才会判断是否进行扩容, 删除元素时传入的是 -1,所以不用进行扩容判断
        if (check >= 0) {
            // nt -> nextTable, sc -> sizeCtl
            Node<K,V>[] tab, nt; int n, sc;

            // s = b + x, b = baseCount.
            // 当元素个数达到 sizeCtl,并且 table长度小于MAXIMUM_CAPACITY,则进行扩容
            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
                   (n = tab.length) < MAXIMUM_CAPACITY) {

                // n -> tab.length.    stamp可确保大小调整不重叠
                int rs = resizeStamp(n);
                if (sc < 0) {
                    // RESIZE_STAMP_SHIFT = 16

                    // 1、(sc >>> RESIZE_STAMP_SHIFT) != rs   ==> sc 向右无符号移动16位后,低16位的值都被舍弃掉了,如果结果为true说明同时
                    //    进行transfer() 操作的线程已经达到了 65535个 ( 1 << 16的值为 65536,而第一个transfer()的线程把sc的值设置为
                    //    ( rs << RESIZE_STAMP_SHIFT) + 2) 本来应该是加1的,多加了1,因此只要同时进行 transfer()的线程达到 65535个,
                    //      结果就会为true.  注意: rs的值是被移动到了高16位,因此sc低16位原来的值是0 );
                    // 2、sc == rs + 1 说明所有执行 transfer()的线程都已经完成了,这就说明扩容的元素转移已经完成,只剩下最后的检查和finishing操作
                    // 3、sc == rs + MAX_RESIZERS 说明进行 transfer()的线程数量已经达到最大了 (MAX_RESIZERS = 65535);
                    // 4、(nt = nextTable) == null 说明已经完成扩容了,完成的操作先修改 nextTable = null,然后再修改sizeCtl的值,因此 sc < 0 时,
                    //    nextTable = null;
                    // 5、transferIndex <= 0 说明原来table上的所有索引位置已经全部分配完成了
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                        transferIndex <= 0)
                        break;

                    // sc 计数+1
                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                        transfer(tab, nt);
                }
                // sc >= 0 . 使用 CAS修改 sc的值为负数,成功才能执行 transfer() 方法
                // 注意: (rs << RESIZE_STAMP_SHIFT) + 2 一定是个负数, sc 小于0 说明正在进行扩容
                // todo: + 2 的作用? 如上第 1 点所述
                else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    transfer(tab, null);


                s = sumCount();
            }
        }
    }

    /**
     * 如果正在调整大小,则帮助转移。
     * Helps transfer if a resize is in progress.
     */
    final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
        Node<K,V>[] nextTab; int sc;

        if (tab != null && (f instanceof ForwardingNode) &&
            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {

            // 根据 tab.length 计算 stamp 值
            int rs = resizeStamp(tab.length);

            // table 扩容时 sizeCtl < 0,否则说明已经完成扩容了
            while (nextTab == nextTable && table == tab &&
                   (sc = sizeCtl) < 0) {

                // 1、(sc >>> RESIZE_STAMP_SHIFT) != rs   ==> sc 向右无符号移动16位后,低16位的值都被舍弃掉了,如果结果为true说明同时
                //    进行transfer() 操作的线程已经达到了 65535个 ( 1 << 16的值为 65536,而第一个transfer()的线程把sc的值设置为
                //    ( rs << RESIZE_STAMP_SHIFT) + 2) 本来应该是加1的,多加了1,因此只要同时进行 transfer()的线程达到 65535个,
                //      结果就会为true.  注意: rs的值是被移动到了高16位,因此sc低16位原来的值是0 );
                // 2、sc == rs + 1 说明所有执行 transfer()的线程都已经完成了,这就说明扩容的元素转移已经完成,只剩下最后的检查和finishing操作
                // 3、sc == rs + MAX_RESIZERS 说明进行 transfer()的线程数量已经达到最大了 (MAX_RESIZERS = 65535);
                // 4、(nt = nextTable) == null 说明已经完成扩容了,完成的操作先修改 nextTable = null,然后再修改sizeCtl的值,因此 sc < 0 时,
                //    nextTable = null;
                // 5、transferIndex <= 0 说明原来table上的所有索引位置已经全部分配完成了
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || transferIndex <= 0)
                    break;

                // 使用CAS把 sc的值设置为 sc + 1,表示多了一个线程进行 transfer()操作
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
                    transfer(tab, nextTab);
                    break;
                }
            }
            return nextTab;
        }
        // 完成扩容,table就是新的表了
        return table;
    }

    /**
     * 尝试调整表的大小以容纳给定的元素数量。
     * Tries to presize table to accommodate the given number of elements.
     *
     * @param size number of elements (doesn't need to be perfectly accurate)
     */
    // size 不是table的大小,而是根据size计算出c的值,c为 table 能容纳的元素个数
    // 若 size 为32,那么 c = 64,table需要扩容到 128
    private final void tryPresize(int size) {
        // MAXIMUM_CAPACITY = 1 << 30
        // tableSizeFor(c) 返回大于等于c的最小的2的幂的数
        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
            tableSizeFor(size + (size >>> 1) + 1);

        int sc;

        // 1、sizeCtl = -1 说明table 正在进行初始化;
        // 2、sizeCtl 是负数,且不等于 -1,说明table正在进行扩容。
        // 若 sc < 0,则什么都不干,方法结束
        // 使用 while 循环的原因是: table 一次扩容只能长度只能增加一倍,而不能一次扩容到想要的长度,
        // 因此只有满足 c <= sc || n >= MAXIMUM_CAPACITY 条件才能结束,或者出现并发,使 sizeCtl < 0
        while ((sc = sizeCtl) >= 0) {
            Node<K,V>[] tab = table; int n;

            // 若 table 还没有初始化
            if (tab == null || (n = tab.length) == 0) {
                // 若 sc > c,则取sc的值,否则取c的值。因为 table初始化之前,sizeCtl保存的是
                // table的初始容量
                n = (sc > c) ? sc : c;
                // 使用CAS修改sc的值为 -1
                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                    try {
                        // 获取到锁(CAS成功)后还需要判断table是否已经被修改了
                        if (table == tab) {
                            // 初始化table
                            @SuppressWarnings("unchecked")
                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                            table = nt;
                            // sc = 0.75 * n
                            sc = n - (n >>> 2);
                        }
                    } finally {
                        // 修改sizeCtl的值,不需要使用CAS,因此此时相当于获取到了锁
                        sizeCtl = sc;
                    }
                }
            }

            // ------  table 已经初始化   -----

            // 只有当 table 能容纳c个元素元素,获取达到了最大容量,才能退出
            else if (c <= sc || n >= MAXIMUM_CAPACITY)
                break;

            // 判断 tab 是否等于table,不等于说明table已经扩容了,继续循环
            else if (tab == table) {
                int rs = resizeStamp(n);
                if (sc < 0) {
                    Node<K,V>[] nt;

                    // RESIZE_STAMP_SHIFT = 16

                    // 1、(sc >>> RESIZE_STAMP_SHIFT) != rs   ==> sc 向右无符号移动16位后,低16位的值都被舍弃掉了,如果结果为true说明同时
                    //    进行transfer() 操作的线程已经达到了 65535个 ( 1 << 16的值为 65536,而第一个transfer()的线程把sc的值设置为
                    //    ( rs << RESIZE_STAMP_SHIFT) + 2) 本来应该是加1的,多加了1,因此只要同时进行 transfer()的线程达到 65535个,
                    //      结果就会为true.  注意: rs的值是被移动到了高16位,因此sc低16位原来的值是0 );
                    // 2、sc == rs + 1 说明所有执行 transfer()的线程都已经完成了,这就说明扩容的元素转移已经完成,只剩下最后的检查和finishing操作
                    // 3、sc == rs + MAX_RESIZERS 说明进行 transfer()的线程数量已经达到最大了 (MAX_RESIZERS = 65535);
                    // 4、(nt = nextTable) == null 说明已经完成扩容了,完成的操作先修改 nextTable = null,然后再修改sizeCtl的值,因此 sc < 0 时,
                    //    nextTable = null;
                    // 5、transferIndex <= 0 说明原来table上的所有索引位置已经全部分配完成了
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                        transferIndex <= 0)
                        break;

                    // sc 计数+1,成功帮忙 transfer()
                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                        transfer(tab, nt);
                }

                // sc >= 0 . 使用 CAS修改 sc的值为负数,成功才能执行 transfer() 方法
                // 注意: (rs << RESIZE_STAMP_SHIFT) + 2 一定是个负数, sc 小于0 说明正在进行扩容
                else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    transfer(tab, null);
            }
        }
    }

    /**
     * 移动 和/或 复制每个bin里面的 nodes 到新的table
     * Moves and/or copies the nodes in each bin to new table. See
     * above for explanation.
     */
    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
        int n = tab.length, stride;

        // (n >>> 3) / NCPU   ->    n / 8 / NCPU
        // MIN_TRANSFER_STRIDE = 16,   stride的值至少为 16
        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
            stride = MIN_TRANSFER_STRIDE; // subdivide range  细分范围

        // 初始化 nextTab、 nextTable、transferIndex
        if (nextTab == null) {            // initiating
            try {
                // 新创建一个数组,大小为原来的两倍
                @SuppressWarnings("unchecked")
                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
                // 初始化 nextTab
                nextTab = nt;
            } catch (Throwable ex) {      // try to cope with OOME
                // OOME ->  OutOfMemoryError 内存溢出错误
                sizeCtl = Integer.MAX_VALUE;
                return;
            }
            // 赋值 nextTable
            nextTable = nextTab;
            // n -> 旧table的长度
            transferIndex = n;
        }


        int nextn = nextTab.length;
        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
        boolean advance = true;
        // 确保在提交nextTab之前进行清理
        boolean finishing = false; // to ensure sweep before committing nextTab

        // for循环遍历
        for (int i = 0, bound = 0;;) {
            Node<K,V> f; int fh;


            // 线程一旦执行了transfer()方法,则必须等所有的索引位置都分配完成才能退出
            while (advance) {
                int nextIndex, nextBound;

                // --i 先减1再比较, 即每循环一次, i 都会先减 1
                // 如果 --i >= bound,那么只需要把 advance赋值为 false,然后继续往下遍历
                if (--i >= bound || finishing)
                    advance = false;

                // transferIndex -> 创建nextTable时,会赋值为旧table的长度
                // (nextIndex = transferIndex) <= 0 说明原来table上的所有索引位置已经全部分配完成了
                else if ((nextIndex = transferIndex) <= 0) {
                    i = -1;
                    advance = false;
                }

                // nextIndex = transferIndex,  使用CAS修改 transferIndex的值
                else if (U.compareAndSwapInt
                         (this, TRANSFERINDEX, nextIndex,
                          nextBound = (nextIndex > stride ?
                                       nextIndex - stride : 0))) {
                    bound = nextBound;
                    // 从旧table的最后一个索引位置往前遍历,最后一个索引为 transferIndex - 1
                    i = nextIndex - 1;
                    advance = false;
                }
            }

            // n -> 旧table的长度, nextn -> 新table的长度 ( 2n )
            // i < 0 || i >= n 不在旧 table的索引范围内, i + n >= nextn  ===>   i + n >= 2n ===>  i >= n
            if (i < 0 || i >= n || i + n >= nextn) {
                int sc;
                if (finishing) {
                    // 扩容完成, nextTable 置为 null
                    nextTable = null;
                    // 把 nextTab 赋值给 table
                    table = nextTab;
                    // 重新赋值 sizeCtl, 大小为新的 table长度 * 0.75
                    sizeCtl = (n << 1) - (n >>> 1);
                    return;
                }

                /**
                 第一个扩容的线程,执行transfer方法之前,会设置 sizeCtl = (resizeStamp(n) << RESIZE_STAMP_SHIFT) + 2)
                 后续帮其扩容的线程,执行transfer方法之前,会设置 sizeCtl = sizeCtl+1
                 每一个退出transfer的方法的线程,退出之前,会设置 sizeCtl = sizeCtl-1
                 那么最后一个线程退出时:
                 必然有sc == (resizeStamp(n) << RESIZE_STAMP_SHIFT) + 2),即 (sc - 2) == resizeStamp(n) << RESIZE_STAMP_SHIFT
                 */
                // 不相等,说明不到最后一个线程,直接退出transfer方法
                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                    // 最后一个完成移动的线程遍历整个table,等所有索引位置的元素都移动完成之后,才能执行 finishing 操作
                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                        return;
                    // 只有最后一个完成transfer任务的线程能够执行到这里,其他线程都直接返回了
                    finishing = advance = true;
                    // 所有的索引位置都要检查一遍
                    i = n; // recheck before commit
                }
            }

            // 若索引i没有元素,则设置为 ForwardingNode
            else if ((f = tabAt(tab, i)) == null)
                // CAS成功则 advance = true,继续处理下一个slot,失败则继续
                advance = casTabAt(tab, i, null, fwd);

            else if ((fh = f.hash) == MOVED)
                // 该索引位置已经完成了元素移动
                advance = true; // already processed        已处理
            else {
                // 首先需要先拿到索引第一个元素的锁(监视器)
                synchronized (f) {
                    // 拿到锁后需要判断该索引的第一个元素是否还是f,如果不是,继续循环
                    if (tabAt(tab, i) == f) {
                        // ln -> 低索引位置的第一个元素   hn -> 高索引位置的第一个元素
                        // 比如原来的长度为16,若索引位置3的元素如果第5位(1 0000)是1那么分配到
                        // 高索引位置19上,否则还是在索引位置3上
                        Node<K,V> ln, hn;
                        if (fh >= 0) {
                            int runBit = fh & n;
                            Node<K,V> lastRun = f;
                            // todo: 为什么要把最后一个元素先取出来
                            //    -->  因为:1、最后一个节点的next字段肯定不会改变,一定是 null,可以重用这个节点
                            //               2、还有一个作用就是,如果线程使用原来的table进行遍历,那么在遍历之前
                            //                  新插入的节点还能被看到
                            for (Node<K,V> p = f.next; p != null; p = p.next) {
                                int b = p.hash & n;
                                if (b != runBit) {
                                    runBit = b;
                                    lastRun = p;
                                }
                            }
                            // 比如长度为 16 (1 0000), 那么最后一个元素hash值的第五位如果是0,那么就赋值给 ln,
                            // 第五位如果是1,那么就赋值给 hn
                            if (runBit == 0) {
                                ln = lastRun;
                                // hn 还没初始化,所以初始化为 null
                                hn = null;
                            }
                            else {
                                hn = lastRun;
                                // ln 还没初始化,所以初始化为 null
                                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)
                                    // 重新创建节点的原因的: 其他线程可能还在进行遍历,因此不能修改原来节点的 next字段,只能重新创建
                                    // 重新创建Node,并传入了 next
                                    ln = new Node<K,V>(ph, pk, pv, ln);
                                else
                                    hn = new Node<K,V>(ph, pk, pv, hn);
                            }

                            // 把ln、 hn 赋值到新table相应的位置上
                            setTabAt(nextTab, i, ln);
                            setTabAt(nextTab, i + n, hn);
                            // 原来table的 i索引位置上的元素赋值为 fwd (ForwardingNode)
                            setTabAt(tab, i, fwd);
                            // 设置 advance = true,继续往下遍历
                            advance = true;
                        }
                        else if (f instanceof TreeBin) {
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            // lo -> 低位的第一个元素,loTail -> 低位的最后一个元素
                            TreeNode<K,V> lo = null, loTail = null;
                            TreeNode<K,V> hi = null, hiTail = null;
                            int lc = 0, hc = 0;
                            // 使用链表进行遍历
                            for (Node<K,V> e = t.first; e != null; e = e.next) {
                                int h = e.hash;
                                // 创建新的节点,保持原来的结构不变
                                TreeNode<K,V> p = new TreeNode<K,V>
                                    (h, e.key, e.val, null, null);

                                if ((h & n) == 0) {
                                    // 设置 p.prev = loTail
                                    if ((p.prev = loTail) == null)
                                        lo = p;
                                    else
                                        // loTail不为null,设置loTail.next = p
                                        loTail.next = p;
                                    // 低位最后一个元素设置为p
                                    loTail = p;
                                    ++lc;   // 低位元素个数 + 1
                                }

                                else {
                                    // 设置 p.prev = loTail
                                    if ((p.prev = hiTail) == null)
                                        hi = p;
                                    else
                                        // hiTail不为null,设置hiTail.next = p
                                        hiTail.next = p;
                                    // 高位最后一个元素设置为p
                                    hiTail = p;
                                    ++hc;  // 高位元素个数 + 1
                                }
                            }
                            // UNTREEIFY_THRESHOLD = 6, 如果扩容后元素个数小于等于6,那么把红黑树转成链表
                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                                    // 如果高位的元素个数为0,说明扩容后元素全部分配到低位上,直接使用原来的TreeBin
                                    // 否则重新构造新的TreeBin
                                (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);
                            // 扩容后把该索引位置上的元素设置为:ForwardingNode
                            setTabAt(tab, i, fwd);
                            advance = true;
                        }
                    }
                }
            }
        }
    }

    /* ---------------- Counter support -------------- */

    /**
     * 用于分配计数的填充单元格.改编自LongAdder and Striped64
     * A padded cell for distributing counts.  Adapted from LongAdder
     * and Striped64.  See their internal docs for explanation.
     */
    @sun.misc.Contended static final class CounterCell {
        volatile long value;
        CounterCell(long x) { value = x; }
    }

    // 统计元素个数, 并发更新下不保证是准确的值
    final long sumCount() {
        CounterCell[] as = counterCells; CounterCell a;
        // 统计 baseCount 和 counterCells中的每个元素总和
        long sum = baseCount;
        if (as != null) {
            // 遍历 counterCells
            for (int i = 0; i < as.length; ++i) {
                if ((a = as[i]) != null)
                    sum += a.value;
            }
        }
        return sum;
    }

    // See LongAdder version for explanation
    private final void fullAddCount(long x, boolean wasUncontended) {
        int h;
        // ThreadLocalRandom.getProbe() 获取当前线程的probe值,如果probe值为0,那么则初始化线程的probe值
        if ((h = ThreadLocalRandom.getProbe()) == 0) {
            // 初始化当前线程的probe值
            ThreadLocalRandom.localInit();      // force initialization
            h = ThreadLocalRandom.getProbe();
            wasUncontended = true;
        }
        boolean collide = false;                // True if last slot nonempty
        for (;;) {
            CounterCell[] as; CounterCell a; int n; long v;

            // 判断 counterCells 不为null, 且长度大于 0
            if ((as = counterCells) != null && (n = as.length) > 0) {

                // 如果当前线程对应的索引位置的元素为 null
                if ((a = as[(n - 1) & h]) == null) {

                    // 判断锁是否可以获取
                    if (cellsBusy == 0) {            // Try to attach new Cell

                        // 乐观地创建(乐观情况下可以获取到锁,因此先创建好 CounterCell)
                        CounterCell r = new CounterCell(x); // Optimistic create

                        // 使用CAS把 cellsBusy 的值从 0修改为1, 从而获取锁
                        if (cellsBusy == 0 &&
                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {

                            boolean created = false;
                            try {               // Recheck under lock
                                CounterCell[] rs; int m, j;

                                // 获取到锁后需要再次判断,重新获取counterCells是因为: counterCells可能已经扩容了,不是原来那个数组了,
                                // 再次判断该索引位置的元素是否为空的原因是:其他线程可能已经更新的该索引位置的值,有可能不为null了
                                if ((rs = counterCells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {

                                    // 不需要使用UNSAFE进行更新,因为 finally{} 会更新 cellsBusy的值,而cellsBusy是volatile修饰的,
                                    // 修改cellsBusy之前所有的缓存数据都会被刷新到主存
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                // 释放锁,同时由于 cellsBusy是volatile修饰的,因此可以把缓存中的数据都刷新到主存,保证对
                                // counterCells的修改立即对其他线程可见
                                cellsBusy = 0;
                            }
                            if (created)
                                // 把第一个值放入CounterCell后就相当于完成了加法操作,因此直接break
                                break;

                            // 该索引位置现在不为null了,continue
                            continue;           // Slot is now non-empty
                        }
                    }

                    // collide 只有在相应的slot不为null且 CAS失败才会为true,此时检查到
                    // slot 为null,说明 countCells扩容了,因此修改 collide = false
                    collide = false;
                }

                // --------     该索引位置上已经有元素了   ---------

                // 如果 wasUncontended = false, 说明调用这个方法之前该索引位置已经使用CAS更新过一次
                // 并且失败了
                else if (!wasUncontended)       // CAS already known to fail
                    // 下面会修改线程 probe的值,相当于修改了该线程对应countCells的索引,然后进行重试
                    wasUncontended = true;      // Continue after rehash

                // *** 该索引位置上的CounterCell不为空,使用CAS更新数据,就算countCells已经扩容了,那么也没有关系,
                //     因为新的 countCells 数据上的元素指向的还是旧countCells上的元素,都是指向相同的对象,
                //     在旧countCells上更新数据也是一样的
                // * 如果CAS失败了,那么下面的else if 还会继续判断
                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                    break;

                // counterCells 已经达到了最大的长度 或者 counterCells != as(counterCells扩容了)
                else if (counterCells != as || n >= NCPU)
                    // 设置 collide = false, 因为此时 collide 可能为 true
                    // 然后下面会修改线程probe的值
                    collide = false;            // At max size or stale

                else if (!collide)
                    // 第一次冲突只设置 collide = true, 然后下面会修改线程 probe的值,
                    // 如果下次还是再冲突,那么就会对 countCells进行扩容
                    collide = true;

                // 连续两次冲突,获取锁
                else if (cellsBusy == 0 &&
                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                    try {
                        // 判断其他线程是否已经对counterCells进行了扩容
                        if (counterCells == as) {// Expand table unless stale
                            // 长度扩大一倍
                            CounterCell[] rs = new CounterCell[n << 1];
                            for (int i = 0; i < n; ++i)
                                // 把旧 counterCells中的元素都赋值到新的 counterCells中
                                rs[i] = as[i];
                            counterCells = rs;
                        }
                    } finally {
                        // 释放锁,同时由于 cellsBusy是volatile修饰的,因此可以把缓存中的数据都刷新到主存,保证对
                        // counterCells的修改立即对其他线程可见
                        cellsBusy = 0;
                    }
                    // 修改collide = false
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                h = ThreadLocalRandom.advanceProbe(h);
            }

            // -------     counterCells 还没有初始化    -------------------

            // 获取锁
            else if (cellsBusy == 0 && counterCells == as &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                boolean init = false;
                try {                           // Initialize table
                    // 判断 counterCells是否已经被其他线程初始化了
                    if (counterCells == as) {
                        // 初始化counterCells, 初始容量为 2
                        CounterCell[] rs = new CounterCell[2];
                        // 创建CounterCell,value为要相加的值x, 并把counterCell放入 counterCells 相应的索引位置
                        rs[h & 1] = new CounterCell(x);
                        counterCells = rs;
                        init = true;
                    }
                } finally {
                    // 释放锁,同时由于 cellsBusy是volatile修饰的,因此可以把缓存中的数据都刷新到主存,保证对
                    // counterCells的修改立即对其他线程可见
                    cellsBusy = 0;
                }
                if (init)
                    // 因为要相加的值已经放入了 CounterCell中,等价于完成了相加,因此方法结束
                    break;
            }

            // countCells 已经被其他线程初始化,或者其他线程已经拿到了 cellsBusy锁
            // 更新baseCount 的值
            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
                // 回到使用 base
                break;                          // Fall back on using base
        }
    }

    /* ---------------- Conversion from/to TreeBins -------------- */

    /**
     * 把容器中给定索引位置的链表节点替换成树节点,除非table太小,这种情况下将对table进行扩容
     * Replaces all linked nodes in bin at given index unless table is
     * too small, in which case resizes instead.
     */
    private final void treeifyBin(Node<K,V>[] tab, int index) {
        Node<K,V> b; int n, sc;
        if (tab != null) {

            // MIN_TREEIFY_CAPACITY = 64,如果table长度没有达到 64,那么不会把链表转成红黑树,只会对table进行扩容
            if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
                // 如果table的长度为 16,即 n = 16, (n << 1) 的值为32,tryPresize(32)会把table的长度扩大到128
                tryPresize(n << 1);

            // b.hash >= 0 说明 b节点属于 链表节点
            else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
                // 获取锁,使用链表的第一个节点作为锁
                synchronized (b) {
                    /**
                     *  转红黑树过程中不判断table是否正在进行扩容是因为:如果在不使用sizeCtl加锁的情况下,判断table没有在
                     *  进行扩容,在转红黑树的过程中还是有可能进行扩容,因此没有什么用。如果进行加锁,那么转红黑树的
                     *  过程中就没办法进行扩容,效率太低。因此不判断。
                     */
                    // 获取到锁后判断第一个节点是否还是原来的节点,如果已经被其他线程转成树节点了,那么不会相等
                    if (tabAt(tab, index) == b) {

                        // hd表示第一个节点,  tl 表示上一个节点
                        TreeNode<K,V> hd = null, tl = null;
                        for (Node<K,V> e = b; e != null; e = e.next) {
                            // 创建 TreeNode,next 、parent 传入 null
                            TreeNode<K,V> p =
                                new TreeNode<K,V>(e.hash, e.key, e.val,
                                                  null, null);

                            // 修改 p 的 prev 节点
                            if ((p.prev = tl) == null)
                                // 如果 tl = null,那么 p 就是第一个节点,所以 hd = p
                                hd = p;
                            else
                                // 上一个节点的 next = p
                                tl.next = p;

                            // tl = p
                            tl = p;
                        }

                        // 把红黑树封装到 TreeBin中,构造方法中会把链表转成红黑树
                        setTabAt(tab, index, new TreeBin<K,V>(hd));
                    }
                }
            }
        }
    }

    /**
     * Returns a list on non-TreeNodes replacing those in given list.
     */
    static <K,V> Node<K,V> untreeify(Node<K,V> b) {
        // hd -> head;   tl 上一个节点
        Node<K,V> hd = null, tl = null;
        for (Node<K,V> q = b; q != null; q = q.next) {
            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
            if (tl == null)
                // tl = null ,说明p 是第一个节点
                hd = p;
            else
                // 修改上一个节点的next
                tl.next = p;
            tl = p;
        }
        return hd;
    }

    /* ---------------- TreeNodes -------------- */

    /**
     * Nodes for use in TreeBins
     */
    static final class TreeNode<K,V> extends Node<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        // 删除节点的时候需要修改上一个的节点的 next 值
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;

        TreeNode(int hash, K key, V val, Node<K,V> next,
                 TreeNode<K,V> parent) {
            super(hash, key, val, next);
            this.parent = parent;
        }

        Node<K,V> find(int h, Object k) {
            return findTreeNode(h, k, null);
        }

        /**
         * 从调用这个方法的节点开始查找,没有找到返回null
         * Returns the TreeNode (or null if not found) for the given key
         * starting at given root.
         */
        final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
            if (k != null) {
                // 从调用这个方法的 TreeNode开始查找
                TreeNode<K,V> p = this;
                do  {
                    int ph, dir; K pk; TreeNode<K,V> q;
                    TreeNode<K,V> pl = p.left, pr = p.right;

                    if ((ph = p.hash) > h)
                        // ph > h 从左子树查找
                        p = pl;
                    else if (ph < h)
                        // ph < h 从右子树查找
                        p = pr;

                    // ----- hash值相等 ------
                    else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                        // p.key 和 key 比较,只有当 p.key == key || k.equals(pk)时才是相等
                        // 找到了,返回
                        return p;
                    else if (pl == null)
                        // p左儿子儿子为空,所以只能从右儿子开始找
                        p = pr;
                    else if (pr == null)
                        // p右儿子为空,所以只能从左儿子开始找
                        p = pl;

                    // 走到这里说明哈希值相等 且 p.key != k 且 k.equals(pk) == false 且 左右子树都不为空
                    else if ((kc != null ||
                              (kc = comparableClassFor(k)) != null) &&
                             (dir = compareComparables(kc, k, pk)) != 0)

                        // comparable 比较结果不相等
                        p = (dir < 0) ? pl : pr;

                    // 哈希值相等 且 ( kc == null 或者comparable比较结果相等),这种情况下没有办法判断是从左子树
                    // 去查找还是从右子树去查找,所以左右子树都要查找

                    // 首先从右子树去查找,没有找到再从左子树去查找
                    // 这里先从左子树去查找可能会好一点,因为比较结果相等的元素都插入在左子树,旋转后才会到右子树
                    /**
                     *                  P
                     *                /   \
                     *               L     R
                     *             /  \   /  \
                     *            L1  L2 R1  R2
                     *     比如 p.key 和 key 不相等,然后又无法知道从P的左节点还是右节点去查找,那么先从R
                     *     节点开始往下查找,如果没找到再从 L节点去查找
                     */
                    else if ((q = pr.findTreeNode(h, k, kc)) != null)
                        // q != null 说明找到了,返回
                        return q;
                    else
                        // 从右子树中没有找到,继续从左子树中查找
                        p = pl;

                    // 当 p = null的时候结束查找
                } while (p != null);
            }

            // 如果没有找到 p.key == key || k.equals(pk) 的元素,那么返回null
            return null;
        }
    }

    /* ---------------- TreeBins -------------- */

    /**
     * TreeBin 不保存用户的keys 和 values,而是指向treenode列表及其根。
     * TreeNodes used at the heads of bins. TreeBins do not hold user
     * keys or values, but instead point to list of TreeNodes and
     * their root.
     * 它们还维护一个寄生的读写锁,迫使写者(持有bin锁的人)在树重组操作之前等待读者(不持有的人)完成。
     * They also maintain a parasitic read-write lock
     * forcing writers (who hold bin lock) to wait for readers (who do
     * not) to complete before tree restructuring operations.
     */
    static final class TreeBin<K,V> extends Node<K,V> {
        TreeNode<K,V> root;
        // 链表的第一个节点,不一定是根节点
        volatile TreeNode<K,V> first;
        volatile Thread waiter;
        // 锁
        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
        // 读锁自增值,每一个线程获取读锁,lockState + 4
        static final int READER = 4; // increment value for setting read lock

        /**
         * Tie-breaking utility for ordering insertions when equal
         * hashCodes and non-comparable. We don't require a total
         * order, just a consistent insertion rule to maintain
         * equivalence across rebalancings. Tie-breaking further than
         * necessary simplifies testing a bit.
         */
        static int tieBreakOrder(Object a, Object b) {
            int d;
            if (a == null || b == null ||
                    // 比较类名
                (d = a.getClass().getName().
                 compareTo(b.getClass().getName())) == 0)
                // 如果类名比较结果相同,使用系统生成的哈希值进行判断
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                     -1 : 1);
            return d;
        }

        /**
         * Creates bin with initial set of nodes headed by b.
         */
        TreeBin(TreeNode<K,V> b) {
            super(TREEBIN, null, null, null);
            // 把 b 赋值给 first
            this.first = b;
            // r 代表根节点
            TreeNode<K,V> r = null;
            for (TreeNode<K,V> x = b, next; x != null; x = next) {
                next = (TreeNode<K,V>)x.next;

                // 初始化left、 right 字段
                x.left = x.right = null;
                if (r == null) {
                    // 若根节点为null, 那么 x 设置为根节点,根节点颜色为黑色,所以 red = false
                    x.parent = null;
                    x.red = false;
                    r = x;
                }
                else {
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for (TreeNode<K,V> p = r;;) {
                        // dir: direction -> 插入左节点还是右节点
                        // ph -> p的哈希值
                        // pk -> p的键
                        int dir, ph;
                        K pk = p.key;

                        // p 的哈希值大于插入key 的哈希值
                        if ((ph = p.hash) > h)
                            // -1 -> 在左子树
                            dir = -1;
                        else if (ph < h)
                            // 1 -> 在右子树
                            dir = 1;

                        // 先使用哈希值判断,哈希值相等再使用Comparable判断(如果插入的键类型是class C implements Comparable<C> )
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)

                            // key不是class C implements Comparable<C>类型,或者 comparable比较结果相等的话,再使用类名判断,
                            // 如果类名还是相同,再使用系统生成的哈希值进行判断。最后的结果还是可能是相等的,即执行完成之后dir可能还是0
                            dir = tieBreakOrder(k, pk);

                        TreeNode<K,V> xp = p;

                        // 根节点开始,当 (p = (dir <= 0) ? p.left : p.right) == null的时候,xp就是插入元素x的父节点
                        // 比较结果相等的时候插入到左节点
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            // balanceInsertion()平衡红黑树,并返回新的根节点
                            r = balanceInsertion(r, x);
                            break;
                        }
                    }
                }
            }
            this.root = r;

            // 链表、红黑树结构检查
            assert checkInvariants(root);
        }

        /**
         * 获取用于树结构重组的写锁。
         * Acquires write lock for tree restructuring.
         */
        private final void lockRoot() {
            // 获取写锁,修改 TreeBin的 lockState值,lockState的值为0才能获取到锁,也就是没有其他线程获取到读锁/写锁
            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
                // 竞争锁
                contendedLock(); // offload to separate method
        }

        /**
         * 释放写锁
         * Releases write lock for tree restructuring.
         */
        private final void unlockRoot() {
            // 释放写锁,把 lockState的值修改成 0
            lockState = 0;
        }

        /**
         * 可能阻塞等待 root lock
         * Possibly blocks awaiting root lock.
         */
        private final void contendedLock() {
            boolean waiting = false;
            // 如果有线程已经获取到了读锁(线程走到这里,不会有其他线程获取到写锁),并且lockState的第二位为1,
            // 那么线程会一直自旋
            for (int s;;) {

                // WAITER = 2
                // ~WAITER -> 1111 1111 1111 1101(低16位)
                // ((s = lockState) & ~WAITER) == 0 ==> lockState 等于 0 或者 2 表示没有线程获取到读锁
                if (((s = lockState) & ~WAITER) == 0) {

                    // lockState = 2 的时候表示当前线程正在等待获取写锁(不可能是其他线程,想要插入或删除元素需要先拿到第一个元素的锁)
                    // 使用CAS把 lockState 的值修改为1,尝试获取写锁, (当 lockState = 0 或者 2 的时候可以获取写锁)
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
                        // 如果 waiting = true,把 waiter设置为null
                        if (waiting)
                            // 因为插入数据需要先获取到第一个节点的锁,因此不会同时有两个线程进入这里,所以waiter不可能是
                            // 其他线程,从而可以直接把 waiter设置为null。
                            waiter = null;
                        return;
                    }
                }

                // WAITER = 2 -> 0000 0000 0000 0010 (低16位)
                else if ((s & WAITER) == 0) {
                    // lockState != 2

                    // 使用 CAS把 lockState 的第二位设置为1,其他位不变。表明有线程在等待写锁
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
                        // waiting 设置为 true,   waiter设置为当前线程
                        waiting = true;
                        // 因为已经设置了lockState的第二位为1,如果waiter不为null,那么最后一个释放读锁的线程
                        // 在释放读锁后会唤醒waiter线程。  如果线程在设置waiter之前,最后一个持有读锁的线程释放了
                        // 读锁,那么也没有关系,因为设置完waiter后还会再尝试获取一次锁,而这次一定能够获取到锁
                        waiter = Thread.currentThread();
                    }
                }

                // 如果有线程持有读锁,并且lockState的第二位已经设置成1了,且waiting = true,那么阻塞当前线程
                else if (waiting)
                    // 阻塞当前线程
                    LockSupport.park(this);
            }
        }

        /**
         * 返回匹配的节点,如果没有则返回null。尝试从根目录使用树比较进行搜索,
         * 但在锁定不可用时继续使用线性搜索。
         * Returns matching node or null if none. Tries to search
         * using tree comparisons from root, but continues linear
         * search when lock not available.
         */
        final Node<K,V> find(int h, Object k) {
            if (k != null) {
                for (Node<K,V> e = first; e != null; ) {
                    int s; K ek;
                    //  WAITER = 2 -> 0000 0000 0000 0010(低16位)
                    //  WRITER = 1 -> 0000 0000 0000 0001(低16位)
                    //  WAITER|WRITER  -> 0000 0000 0000 0011(低16位)
                    //  ((s = lockState) & (WAITER|WRITER)) != 0 说明有线程已经获取到了写锁,或者等待获取写锁,
                    //  因此线程不能获取读锁,使用链表方式进行查找
                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
                        if (e.hash == h &&
                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
                            // 找到,返回
                            return e;
                        // 没有找到遍历下一个节点
                        e = e.next;
                    }

                    // 一旦发现线程释放了写锁,并且没有线程等待获取写锁,那么将尝试获取读锁,使用红黑树查找的方法,
                    // 从根节点开始查找 (不能从正在遍历的节点开始查找,因为链表的顺序和红黑树的顺序完全没有联系)
                    // READER = 4 一个线程获取到读锁,lockState的值 + 4
                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
                                                 s + READER)) {
                        // 进入这里,说明已经成功获取到了读锁

                        TreeNode<K,V> r, p;
                        try {
                            // 如果根节点为 null,那么 p = null,方法返回p; 否则从根节点开始查找
                            p = ((r = root) == null ? null :
                                 r.findTreeNode(h, k, null));
                        } finally {
                            Thread w;
                            // 释放锁,U.getAndAddInt() 循环使用CAS设置值,直到成功为止,并返回修改之前的值
                            // WAITER = 2 -> 0000 0000 0000 0010(低16位)
                            // READER = 4 -> 0000 0000 0000 0100(低16位)
                            // 修改之前lockSate的值为:0000 0000 0000 0110(低16位) 表示该线程是最后一个持有
                            // 读锁的线程,并且有线程正在等待获取写锁, 并且此时 waiter 不为null,那么唤醒等待获取
                            // 写锁的线程
                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
                                (READER|WAITER) && (w = waiter) != null)
                                // 唤醒线程
                                LockSupport.unpark(w);
                        }
                        return p;
                    }
                }
            }
            return null;
        }

        /**
         * Finds or adds a node.
         * null 表示添加了新的节点,否则返回 key映射的节点
         * @return null if added
         */
        // h -> 哈希值
        final TreeNode<K,V> putTreeVal(int h, K k, V v) {
            Class<?> kc = null;
            // searched 表示是否已经在整个红黑树中查找过 key是否存在了
            boolean searched = false;

            for (TreeNode<K,V> p = root;;) {
                // dir: direction -> 插入左节点还是右节点
                // ph -> p的哈希值
                // pk -> p的键
                int dir, ph; K pk;
                // 如果树中没有任何节点,那么创建新的节点,并设置和 first 和 root
                if (p == null) {
                    first = root = new TreeNode<K,V>(h, k, v, null, null);
                    break;
                }

                // p 的哈希值大于插入key 的哈希值
                else if ((ph = p.hash) > h)
                    // -1 -> 在左子树
                    dir = -1;
                else if (ph < h)
                    // 1 -> 在右子树
                    dir = 1;
                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                    // p.key == key 或者 equals()方法返回true才是真正的相等,comparable只是比较一下存放的位置
                    // key 已存在, 返回已存在的节点,putVal()方法会判断是否更新原来的值
                    return p;

                // 先判断哈希值,哈希值相等且equals()方法返回false时才会使用 comparable判断
                else if ((kc == null &&
                        // comparableClassFor(k) 判断k 是否是 class C implements Comparable<C>
                          (kc = comparableClassFor(k)) == null) ||
                        // k -> 要插入的元素的key, pk -> p的 key
                        // 使用comparable 比较,若比较结果相等也相等(不能判断插入的元素是在左边还是在右边)
                         (dir = compareComparables(kc, k, pk)) == 0) {

                    // searched 初始值为false
                    if (!searched) {
                        TreeNode<K,V> q, ch;
                        searched = true;

                        // p这个元素在上面已经判断过不相等了,所以只要从左儿子开始找,左儿子没有找到再从右儿子去找
                        // -- 为什么从左儿子开始找,而不是右儿子? 因为哈希值dir = 0的时候,元素是存到左子树,只有旋转了
                        // 元素才可能跑到右子树,所以先从左儿子去找,找到元素的可能性比较大。
                        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);
                }

                // 通过上面的查找确定key在树中不存在,才能进行插入
                TreeNode<K,V> xp = p;
                // 哈希值相等,equals方法返回false的时候 dir = 0,等于0插入到左子树
                // dir = 0的情况:哈希值相等,equals方法返回false,且comparable比较结果为0,且key在红黑树中不存在
                // p == null 的时候, xp就是要就是插入节点的父节点
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    TreeNode<K,V> x, f = first;
                    // first 指向新的节点,新节点的next指向原来的first (这个和HashMap不一样)
                    // 构造方法传入 f ,设置了新 first的 next 节点,避免链表在一瞬间内断开连接
                    first = x = new TreeNode<K,V>(h, k, v, f, xp);

                    // 修改原来 first 的prev节点
                    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 {
                            // todo : 为什么释放写锁不用考虑唤醒其他线程?
                            //  --->   因为插入数据的时候需要先拿到第一个节点的锁,因此不存在两个线程同时修改
                            // 同一个索引上数据,从而线程只会等待读锁释放,而不会存在等待写锁释放的情况,所以释放
                            // 写锁的时候不用考虑唤醒其他线程
                            // 释放写锁。
                            unlockRoot();
                        }
                    }
                    break;
                }
            }
            assert checkInvariants(root);
            return null;
        }

        /**
         * 删除给定的节点,在调用这个方法之前,必须先确定删除节点存在
         * Removes the given node, that must be present before this
         * 这比典型的红黑删除代码更混乱,因为我们不能使用右子树的最小节点来交换内部节点的内容,
         * 因为"next"固定了节点的顺序,而“next”指针是可以独立于lock访问的。
         * call.  This is messier than typical red-black deletion code
         * because we cannot swap the contents of an interior node
         * with a leaf successor that is pinned by "next" pointers
         * that are accessible independently of lock. So instead we
         * 所以我们交换树状连杆。
         * swap the tree linkages.
         *
         *          如果删除后红黑树的结构太小,那么返回true,表示需要把红黑树转成链表
         * @return true if now too small, so should be untreeified
         */
        final boolean removeTreeNode(TreeNode<K,V> p) {
            TreeNode<K,V> next = (TreeNode<K,V>)p.next;
            TreeNode<K,V> pred = p.prev;  // unlink traversal pointers
            TreeNode<K,V> r, rl;
            if (pred == null)
                // pred = null,说明删除的节点是 第一个节点
                first = next;
            else
                // pred.next = next,即把要删除的节点从链表中删除
                pred.next = next;

            // 如果next 不为null,修改 next的prev节点
            if (next != null)
                next.prev = pred;

            if (first == null) {
                root = null;
                // 该索引位置没有任何节点了,返回true,把红黑树节点转成链表节点
                return true;
            }

            // 红黑树的结构至少要是以下这样的,否则返回true,把红黑树转成链表
            //                    root
            //                    /  \
            //                  rl    rr
            //                  /
            //                 rll
            // r = root
            if ((r = root) == null || r.right == null || // too small
                (rl = r.left) == null || rl.left == null)
                return true;

            // 获取写锁,对红黑树的结构更新,需要获取到写锁
            lockRoot();
            try {
                TreeNode<K,V> replacement;
                TreeNode<K,V> pl = p.left;
                TreeNode<K,V> pr = p.right;

                // 删除节点的左右子树都不为null
                if (pl != null && pr != null) {
                    TreeNode<K,V> s = pr, sl;
                    //        p
                    //       / \
                    //     pl  s(pr)
                    //         /
                    //        sl
                    // 1、查找右子树中最小的元素,比如上图中的s1
                    while ((sl = s.left) != null) // find successor
                        s = sl;

                    // 现在 s 是删除元素右子树中最小的元素
                    // 2、 s 和 p 互换颜色和位置,然后再去删除p

                    //   2.1 互换颜色
                    boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                    // 右子树中最小的元素左节点一定为空,所以只要先把s的右节点保存下来就行了
                    TreeNode<K,V> sr = s.right;
                    TreeNode<K,V> pp = p.parent;

                    //  2.2 把S 和 P互换位置

                    // 判断s(右子树最小的元素) 是否是 p的右节点,这个判断很重要,否则就会出现 p.parent = p
                    if (s == pr) { // p was s's direct parent
                        // s 的右子树已经赋值给 sr了,下面会把sr 添加到 p的右子树
                        p.parent = s;   // p.right,p.left 还没修改,下面会去修改,和else情况是公共的逻辑
                        s.right = p;    // s.left,s.parent 还没修改,下面会去修改,和else情况是公共的逻辑
                    }
                    // s不是p的右节点
                    else {
                        TreeNode<K,V> sp = s.parent;
                        if ((p.parent = sp) != null) {
                            if (s == sp.left)  // s 在 sp的左子树
                                sp.left = p;  // sp的左子树变成 p
                            else
                                sp.right = p; // sp的右子树变成 p
                        }
                        // s.right = pr
                        if ((s.right = pr) != null)
                            pr.parent = s;
                    }

                    // p 和 s互换位置,s是p右子树的最小元素,所以s的左子树一定为空,换位置后 p.left = null
                    p.left = null;

                    // p.right = sr
                    if ((p.right = sr) != null)
                        sr.parent = p;

                    // s.left = pl
                    if ((s.left = pl) != null)
                        pl.parent = s;

                    // s.parent = pp
                    if ((s.parent = pp) == null)
                        // pp == null,说明p是根节点,换位置后s变成根节点,这里只是把s赋值给了r,并没有赋值给root
                        r = s;

                    // 修改pp的子节点
                    else if (p == pp.left)
                        pp.left = s;
                    else
                        pp.right = s;

                    // 判断sr是否为null,sr不为null,那么删除p节点只要把sr移动到p的位置上,颜色变成 p节点的颜色即可
                    if (sr != null)
                        replacement = sr;
                    else
                        replacement = p;
                }

                // pl、pr 有一个为null,或者全部为null

                else if (pl != null)
                    // 把pl移动到p的位置上,颜色变成p的颜色即可 (这种情况pl的颜色一定是红色,所以p的颜色一定是黑色)
                    replacement = pl;
                else if (pr != null)
                    // 把 pr移动到p的位置上,颜色变成p的颜色即可
                    replacement = pr;
                else
                    // 这种情况如果p节点的颜色不是红色的,那么需要对红黑树进行平衡处理
                    replacement = p;

                // replacement != p ,那么只需要把 replacement移动到 p位置上,把replacement的颜色变成p的颜色即可
                // (replacement != p的情况:1、删除节点有且只有一个节点不为null;2、删除节点移动后,右子节点不为null)
                if (replacement != p) {
                    // 使用replacement节点替换p节点,然后修改颜色是在balanceDeletion() 方法里面
                    TreeNode<K,V> pp = replacement.parent = p.parent;

                    // pp为null,说明p是根节点,然后p的左右子树有一个为null时,有replacement != p,
                    // 但是对红黑树的结构限制后,根节点的左右子节点都不能为null, 因此这种情况不存在
                    // 如果p的左右子树都不为null,那么互换位置后p的父节点pp不可能为null
                    // 因此: replacement != p 时 pp = null不存在
                    if (pp == null)
                        // pp = null说明删除的 p节点是根节点,那么现在 replacement 变成了根节点
                        // 这里只是把 replacement 赋值给了局部变量r,并没有赋值给 root。
                        r = replacement;
                    // 修改父节点的子节点
                    else if (p == pp.left)
                        pp.left = replacement;
                    else
                        pp.right = replacement;

                    // p的左右节点和父亲都设置为null (树节点的遍历需要拿到锁,所以可以进行clear)
                    p.left = p.right = p.parent = null;
                }

                // p的左右节点至少有一个为空,如果p 的颜色是红色的,那么p的左右节点肯定都为空(因为不能连续两个红色的节点)
                // 所以如果p 的颜色是红色的,那么直接删除即可

                // 如果replacement != p那么replacement 一定是红色的,而p一定是黑色的,balanceDeletion()方法会把
                // replacement的颜色变成黑色;如果replacement = p,那么p的颜色可能是红色,也可能是黑色的
                root = (p.red) ? r : balanceDeletion(r, replacement);

                // replacement != p在上面已经把p节点删除了,而 replacement = p还没把p节点删除,
                // 在这里把 p节点删除
                if (p == replacement) {  // detach pointers
                    TreeNode<K,V> pp;
                    // 删除p节点,p == replacement,那么p的左右子节点一定都为null,如果此时p.parent = null,
                    // 那么该索引位置就只剩下p节点了,程序不会走到这里来
                    if ((pp = p.parent) != null) {
                        if (p == pp.left)
                            pp.left = null;
                        else if (p == pp.right)
                            pp.right = null;
                        // p == replacement,那么p的左右子节点一定都为null.所以只需要设置parent = null即可
                        p.parent = null;
                    }
                }
            } finally {
                // 释放锁
                unlockRoot();
            }
            assert checkInvariants(root);
            // 返回false,不需要把红黑树转成链表
            return false;
        }

        /* ------------------------------------------------------------ */
        // Red-black tree methods, all adapted from CLR

        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
                                              TreeNode<K,V> p) {
            TreeNode<K,V> r, pp, rl;
            if (p != null && (r = p.right) != null) {
                if ((rl = p.right = r.left) != null)  // p.right = r.left
                    // 若 r.left != null,修改 r.left.parent = p;
                    rl.parent = p;
                if ((pp = r.parent = p.parent) == null) // r.parent = p.parent
                    // 如果p.parent == null,那么p就是原来的根节点,旋转后r成为新的根节点
                    // root = r, 且设置颜色为黑色
                    (root = r).red = false;
                else if (pp.left == p)
                    // 如果p是pp 的左儿子,修改pp的左儿子为r
                    pp.left = r;
                else
                    // 如果p是pp 的右儿子,修改pp的右儿子为r
                    pp.right = r;
                // 修改r.left = p 和 p.parent = r
                r.left = p;
                p.parent = r;
            }
            // 返回新的根节点(红黑色的根节点而不是子树的根节点)
            return root;
        }

        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
                                               TreeNode<K,V> p) {
            TreeNode<K,V> l, pp, lr;
            if (p != null && (l = p.left) != null) {  // l = p.left
                if ((lr = p.left = l.right) != null)  // p.left = r.right
                    // 如果 r.right != null,修改r.right.parent = p
                    lr.parent = p;
                if ((pp = l.parent = p.parent) == null)  // l.parent = p.parent
                    // 如果p.parent == null,那么p就是原来的根节点,旋转后r成为新的根节点
                    // 并设置颜色为黑色
                    (root = l).red = false;
                    // 修改pp的儿子
                else if (pp.right == p)
                    pp.right = l;
                else
                    pp.left = l;
                l.right = p;
                p.parent = l;
            }
            // 返回新的根节点(红黑色的根节点而不是子树的根节点)
            return root;
        }

        // 方法返回根节点
        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
            // 新插入节点的颜色为红色
            x.red = true;
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {

                if ((xp = x.parent) == null) {
                    // 如果x 是根节点,把x 的颜色修改成黑色
                    x.red = false;
                    // 返回的情况只有两种:
                    // 1、x是根节点的时候返回
                    return x;
                }

                else if (!xp.red || (xpp = xp.parent) == null)
                    // 2、 xp是黑色的了,说明没有两个连续红色的节点了,返回
                    // 如果xp是黑色的 或者 xp.parent == null (说明xp就是根节点,xp是根节点,xp不可能是红色的)
                    return root;

                if (xp == (xppl = xpp.left)) {
                    // xp 是红色的,且xp 是xpp 的左子树
                    if ((xppr = xpp.right) != null && xppr.red) {
                        // xp的兄弟节点是红色的,这种情况不能通过旋转达到平衡,得上溯,
                        // 把 xppl(xp) 和xppr变成黑色,然后xp变成红色的 (xp是红色的,xpp肯定是黑色的)
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        // xp的兄弟节点是黑色的,可以通过旋转达到平衡,但是需要判断单旋转还是双旋转
                        if (x == xp.right) {
                            // 之字形,需要左右旋转。先进行左旋处理

                            //      xpp(b)                                   xpp(b)
                            //      /   \         旋转之前先把x赋值为xp       /    \
                            //    xp(r) xppr(b)   ====>  rotateLeft(x)    x(r)   xppr(b)
                            //      \                                     /
                            //      x(r)                               xp(r)

                            // 旋转之前先把x赋值为xp,通过旋转结果可以明了地看出为什么要把x赋值为xp
                            root = rotateLeft(root, x = xp);    // 旋转后返回新的根节点
                            // 现在x是指向图2中 xp的位置
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }

                        //          xpp(b)                    xp(b)
                        //          /    \                    /   \
                        //       xp(r)   xppr(b)   ===>     x(r)  xpp(r)
                        //        /                                 \
                        //     x(r)                                 xppr(b)
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                // 旋转会返回新的根节点(根节点可能会在旋转后变化,也可能不变)
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                else {
                    // xp 是红色的,且xp 是xpp 的右子树

                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.left) {
                            // 之字形旋转,先进行右转
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

        // x -> replacement
        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
                                                   TreeNode<K,V> x) {
            for (TreeNode<K,V> xp, xpl, xpr;;)  {
                // 这里的 root 是局部变量 root
                if (x == null || x == root)
                    // 如果删除的是根节点,那么会设置 root = s (右子树最小节点),所以这种情况下 x != root
                    // x == root的情况:  1、上溯到根节点,直接返回,此时这棵树的所有路径少了一个黑色节点
                    //                  2、 设置 x = root,退出循环
                    return root;
                else if ((xp = x.parent) == null) {
                    // todo: xp == null 那么 x不就是根节点了吗? 根本不会进入到这里面? 每次旋转后 root都会指向新的根节点
                    // 什么情况下 root 不是根节点? 好像不存在这种情况 (出现并发删除时候可能会出现这种情况)

                    // xp == null 说明x 就是根节点,设置x的颜色为黑色
                    x.red = false;
                    return x;
                }
                else if (x.red) {
                    // replacement != p 时,x(replacement)的颜色一定是红色的,在这会把replacement的颜色变成黑色的

                    // x 的颜色为红色的,设置x的颜色为黑色即可
                    // 1、x不可能是删除的元素本身,因为如果删除的元素是红色的,不会调用这个方法
                    // 2、x可能是删除元素的左节点,或者右节点,此时已经使用x替换了删除元素的位置,只要把颜色设置为黑色即可
                    // 3、上溯过程中,如果x的颜色是红色的,设置为黑色的即可
                    x.red = false;
                    return root;
                }
                else if ((xpl = xp.left) == x) {
                    // x 是xp的左子树

                    // 走到这里说明 x是删除的元素本身而且颜色是黑色,且x 没有子节点
                    // 这时候需要分以下几种情况:
                    // 1、x的兄弟节点s是否是红色的
                    // 2、x的兄弟节点s是黑色,s是否有红色的孩子
                    // 3、x的兄弟节点s是黑色的,且没有红色的孩子,父节点是否是红色的
                    // 4、如果以上情况都不是,s设置为红色,然后上溯,最坏情况下,到达根节点,把根节点的另一个子节点变成红色的,
                    //    这样,整棵树的所有路径少了一个黑色的节点。上溯过程中也始终不会修改根节点的颜色,所以也不用维护根节点的颜色。

                    // xpr -> x的兄弟节点
                    if ((xpr = xp.right) != null && xpr.red) {
                        // 1、 x的兄弟节点是红色,通过旋转解决

//                    P(b)                          S(b)                      S(b)
//                   /   \         第一步           /   \       第二步        /   \
//                 D(b)  S(r)      ====>         P(r)  SR(b)    ====>       P(b)  SR(b)
//                       /  \                    /  \                      /  \
//                    SL(b) SR(b)              D(b) SL(b)                 D(r) SL(r)

                        // 这里只完成了上面的第一步
                        xpr.red = false;  // 兄弟节点颜色变成黑色的
                        xp.red = true;     // xp的颜色变成红色的
                        root = rotateLeft(root, xp);    // 左旋
                        // 旋转后位置变了,重新赋值: xp = x.parent; xpr = xp.right
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }

                    if (xpr == null) // todo: 什么情景? x的颜色是黑色的,所以xpr不可能为空的
                                            // (可能是出现并发删除时会有这种情况)
                        x = xp;
                    else {
                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
                        if ((sr == null || !sr.red) &&
                            (sl == null || !sl.red)) {
                            // ----- 上溯在这里处理 ----

                            // 2、x的兄弟节点xpr是黑色的,且xpr没有红色的孩子,把兄弟节点设置为红色,把 x 指向 xp 进行上溯
                            // 上面的 情景1 的第二步在这里得到解决 (xp是红色的,所以直接设置成黑色的即可)
                            xpr.red = true;
                            x = xp;
                        }
                        else {
                            // 3、S 的左节点是红色的,通过旋转和颜色变换把场景变成场景4

//                    P(b)                         P(b)
//                   /   \                         /   \
//                 D(b)  S(b)      ====>         D(b)  SL(b)
//                       /                               \
//                    SL(r)                              S(R)

                            if (sr == null || !sr.red) { // 如果左右节点都是红色的,那么只需要进行单旋转就行了
                                if (sl != null)
                                    // sl 的颜色设置为黑色的
                                    sl.red = false;
                                xpr.red = true; // 把xpr颜色变成红的
                                root = rotateRight(root, xpr);

                                // xpr指向上图的SL位置
                                xpr = (xp = x.parent) == null ?
                                    null : xp.right;
                            }

                            // 4. S的右节点颜色是红色的
                            //   原理:旋转变色后右子树黑色节点个数不变,左子树黑色节点个数多了一个
//                    P(b)                         S(b)
//                   /   \                         /   \
//                 D(b)  S(b)      ====>         P(b)  SR(b)
//                         \                     /
//                         SR(r)                D(r)

//                    P(r)                         S(r)
//                   /   \                         /   \
//                 D(b)  S(b)      ====>         P(b)  SR(b)
//                         \                     /
//                         SR(r)                D(r)

                            if (xpr != null) {
                                xpr.red = (xp == null) ? false : xp.red; // xp节点也可能是红的,所以设置成xp的颜色
                                if ((sr = xpr.right) != null)
                                    sr.red = false; // 设置sr颜色为黑色的
                            }
                            if (xp != null) {
                                xp.red = false;// 设置xp颜色为黑色的,对应上图的P节点
                                root = rotateLeft(root, xp);
                            }
                            // 通过x = root 退出循环
                            x = root;
                        }
                    }
                }
                else { // symmetric
                    // 删除的元素在父节点的右边

                    if (xpl != null && xpl.red) {
                        xpl.red = false;
                        xp.red = true;
                        root = rotateRight(root, xp);
                        xpl = (xp = x.parent) == null ? null : xp.left;
                    }
                    if (xpl == null)
                        x = xp;
                    else {
                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
                        if ((sl == null || !sl.red) &&
                            (sr == null || !sr.red)) {
                            xpl.red = true;
                            x = xp;
                        }
                        else {
                            if (sl == null || !sl.red) {
                                if (sr != null)
                                    sr.red = false;
                                xpl.red = true;
                                root = rotateLeft(root, xpl);
                                xpl = (xp = x.parent) == null ?
                                    null : xp.left;
                            }
                            if (xpl != null) {
                                xpl.red = (xp == null) ? false : xp.red;
                                if ((sl = xpl.left) != null)
                                    sl.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateRight(root, xp);
                            }
                            x = root;
                        }
                    }
                }
            }
        }

        /**
         * Recursive invariant check
         */
        // 检查链表结构和红黑树结构是否正常
        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
                tb = t.prev, tn = (TreeNode<K,V>)t.next;

            // 检查 tb(tp) 和 t的双向连接是否正确
            if (tb != null && tb.next != t)
                return false;

            // 检查 tn 和 t的双向连接是否正确
            if (tn != null && tn.prev != t)
                return false;

            // 检查 tp 和 t 的节点指向是否正确
            if (tp != null && t != tp.left && t != tp.right)
                return false;

            // 检查 tl 和 t的节点指向是否正确,并比较哈希值,tl的哈希值不能大于t的哈希值
            if (tl != null && (tl.parent != t || tl.hash > t.hash))
                return false;

            // 检查 tr 和 t的节点指向是否正确,并比较哈希值,tr的哈希值不能小于t的哈希值
            if (tr != null && (tr.parent != t || tr.hash < t.hash))
                return false;

            // 检查不能有两个连续的红色节点
            if (t.red && tl != null && tl.red && tr != null && tr.red)
                return false;

            // 递归检查左子树 (使用的是中序遍历)
            if (tl != null && !checkInvariants(tl))
                return false;

            // 递归检查右子树
            if (tr != null && !checkInvariants(tr))
                return false;
            return true;
        }

        private static final sun.misc.Unsafe U;
        private static final long LOCKSTATE;
        static {
            try {
                U = sun.misc.Unsafe.getUnsafe();
                Class<?> k = TreeBin.class;
                LOCKSTATE = U.objectFieldOffset
                    (k.getDeclaredField("lockState"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

    /* ----------------Table Traversal -------------- */

    /**
     * 记录表、表的长度和当前遍历索引,用于必须在处理当前表之前处理已转发表的某个区域的遍历器。
     * Records the table, its length, and current traversal index for a
     * traverser that must process a region of a forwarded table before
     * proceeding with current table.
     */
    static final class TableStack<K,V> {
        // 旧表的长度
        int length;
        // 遍历到旧表的索引位置
        int index;
        // 旧表
        Node<K,V>[] tab;

        TableStack<K,V> next;
    }

    /**
     * 封装遍历方法,如containsValue;还可以作为其他迭代器和spliterator的基类。
     * Encapsulates traversal for methods such as containsValue; also
     * serves as a base class for other iterators and spliterators.
     *
     * 方法预先访问在迭代器构造时可以访问的每个仍然有效的节点。
     * Method advance visits once each still-valid node that was
     * reachable upon iterator construction.
     * 它可能会遗漏一些在访问bin之后添加到bin中的内容,这是wrt一致性的保证。
     * It might miss some that
     * were added to a bin after the bin was visited, which is OK wrt
     * consistency guarantees.
     * 在可能持续调整大小的情况下维护此属性需要相当数量的簿记状态,
     * 在易变访问中很难优化这些状态。尽管如此,遍历仍然保持了合理的吞吐量。
     * Maintaining this property in the face
     * of possible ongoing resizes requires a fair amount of
     * bookkeeping state that is difficult to optimize away amidst
     * volatile accesses.  Even so, traversal maintains reasonable
     * throughput.
     *
     * 通常情况下,迭代会逐箱遍历列表。但是,如果表已经调整了大小,那么以后的所有
     * 步骤都必须遍历当前索引处的bin和在 (index + baseSize)索引处;等等来进一步调整大小。
     * Normally, iteration proceeds bin-by-bin traversing lists.
     * However, if the table has been resized, then all future steps
     * must traverse both the bin at the current index as well as at
     * (index + baseSize); and so on for further resizings. To
     * 为了偏执地处理迭代器用户在线程之间的潜在共享,如果读取的表的边界检查失败,迭代将终止。
     * paranoically cope with potential sharing by users of iterators
     * across threads, iteration terminates if a bounds checks fails
     * for a table read.
     */
    static class Traverser<K,V> {

        // 当前table,扩容会更新
        Node<K,V>[] tab;        // current table; updated if resized

        // 上次遍历返回的节点
        Node<K,V> next;         // the next entry to use

        // stack当前使用的TableStack, spare备份用过的TableStack以重新用
        TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes

        // 当前表遍历的索引位置 (当前正在遍历的表)
        int index;              // index of bin to use next

        // 初始表遍历的索引位置
        int baseIndex;          // current index of initial table

        // 初始表的索引界限
        int baseLimit;          // index bound for initial table

        // 初始表大小
        final int baseSize;     // initial table size

        // containsValue()方法 -> new Traverser<K,V>(t, t.length, 0, t.length)
        Traverser(Node<K,V>[] tab, int size, int index, int limit) {
            this.tab = tab;
            this.baseSize = size;
            this.baseIndex = this.index = index;
            this.baseLimit = limit;
            this.next = null;
        }

        /**
         *  example:
         *    创建 Traverser 时,table为 table1,遍历过程中 table扩容到 table4了,然后进行索引1 的遍历
         *
         *                   table1         table2         table3       table4
         *  length:           16              32            64           128
         *
         * 索引1的元素为:      FWN            FWN            FWN        保存数据Node
         *
         *    1、  this.tab -> table1,获取tab 索引1的元素,该元素是 ForwardingNode,所以 this.tab -> table2,
         *         然后创建 TableStack1 { tab = table1; length = 16; index = 1; next = null },stack = TableStack1;
         *
         *    2、  this.tab -> table2, 获取索引1的元素,该元素是 ForwardingNode,所以 this.tab -> table3,
         *         然后创建 TableStack2 {tab = table2; length = 32; index = 1; next = TableStack1 }, stack = TableStack2;
         *
         *    3、  this.tab -> table3, 获取索引1的元素,该元素是 ForwardingNode,所以 this.tab -> table4,
         *         然后创建 TableStack3 {tab = table3; length = 64; index = 1; next = TableStack2 }, stack = TableStack3;
         *
         *    4、  this.tab -> table4, 获取索引1的元素,成功获取到元素,此时stack = TableStack3 != null,调用 recoverState(128),
         *         index = index + TableStack3.length = 1 + 64 = 65, 65 < 128;
         *
         *    5、  this.tab -> table4, 获取索引65的元素,成功获取到元素(或者没有获取到元素),此时stack = TableStack3 != null,
         *         调用 recoverState(128), index = 65 + 64 = 129, 129 > 128, 所以:
         *         n = 64;  index = 1; tab = table3; next = TableStack2; TableStack3.next = null;
         *         ->   stack = TableStack2  <- ;    spare = TableStack3;
         *         index = 1 + 32  = 33, 33 < 64
         *
         *    6、  this.tab -> table3, 获取索引33的元素,该元素是 ForwardingNode,所以 this.tab -> table4, spare = TableStack3,所以
         *         重用 TableStack3 {tab = table3; length = 64; index = 33; next = TableStack2 }, stack = TableStack3;
         *
         *    7、  this.tab -> table4, 获取索引33的元素,然后获取索引 33 + 64 = 96 的元素, 然后 96 + 64 > 128, 所以:
         *            n = 64;  index = 33; tab = table3; next = TableStack2; TableStack3.next = null;
         *            ->   stack = TableStack2  <- ;    spare = TableStack3;
         *            index = 33 + 32  = 65,  65 > 64, 所以:
         *
         *              n = 32;  index = 1; tab = table2; next = TableStack1; TableStack2.next = TableStack3;
         *              ->   stack = TableStack1  <- ;    spare = TableStack2;
         *
         *
         * 总结:
         *                         table1         table2         table3
         *        length:           16              32            64
         *
         *      遍历table1索引1的元素,-> 遍历table2 索引1的元素 -> 遍历table3索引1、 1 + 32的元素
         *      -> 遍历 table2 索引 1 + 16 = 17 的元素 -> 遍历table3索引 17、 17 + 32 的元素
         *      -> 遍历table2 索引2的元素 .....
         */

        /**
         * 如果可能,则前进,返回下一个有效节点,如果没有,则返回null。
         * Advances if possible, returning next valid node, or null if none.
         */
        final Node<K,V> advance() {
            Node<K,V> e;
            // next 是上次遍历返回的元素
            if ((e = next) != null)
                // 遍历下一个元素
                e = e.next;

            for (;;) {
                Node<K,V>[] t; int i, n;  // must use locals in checks
                if (e != null)
                    // 把 e 赋值给next,用于下次遍历,然后返回 e
                    return next = e;

                // baseIndex >= baseLimit  超过限定的索引位置
                // (n = t.length) <= (i = index)  超出表的索引位置,遍历完成
                // i < 0   索引小于0
                if (baseIndex >= baseLimit || (t = tab) == null ||
                    (n = t.length) <= (i = index) || i < 0)
                    // 设置next = null,并返回 null
                    return next = null;

                // i = index
                if ((e = tabAt(t, i)) != null && e.hash < 0) {
                    if (e instanceof ForwardingNode) {
                        // tab指向新的表
                        tab = ((ForwardingNode<K,V>)e).nextTable;
                        e = null;
                        // t = tab 上一个 table,  i = index,  n 上一个table的长度
                        pushState(t, i, n);     // 保存当前表的遍历状态
                        // 继续循环, 索引位置不变,从下一个表去查找
                        continue;
                    }
                    else if (e instanceof TreeBin)
                        // 如果是 TreeBin,把第一个节点赋值给 e
                        e = ((TreeBin<K,V>)e).first;
                    else
                        e = null;
                }

                if (stack != null)
                    // n -> 新表的长度
                    recoverState(n);    // 重新获取遍历状态

                /**
                 * 虽然元素转移是从后往前进行transfer()的,但是有可能是多线程同时进行transfer(),因此当遇到
                 * ForwardingNode节点后,下一个索引的元素可能不是 ForwardingNode,因此出现stack != null之后,
                 * 遍历后续的索引位置,stack还可能为null
                 */
                // this.tab 不为初始化表的时候, stack 不会为null
                else if ((index = i + baseSize) >= n)
                    // baseIndex + 1 然后赋值给 index
                    index = ++baseIndex; // visit upper slots if present   如果有的话,访问上面的槽
            }
        }

        /**
         * 保存遇到转发节点时的遍历状态。
         * Saves traversal state upon encountering a forwarding node.
         */
        private void pushState(Node<K,V>[] t, int i, int n) {
            // 如果 spare 不为null的话,那么重新使用 spare,避免频繁创建对象,
            // 扩容n次,只需要创建 n个 TableStack 对象就够了
            TableStack<K,V> s = spare;  // reuse if possible
            if (s != null)
                spare = s.next;
            else
                // 创建一个 TableStack
                s = new TableStack<K,V>();
            // 保存遍历状态
            s.tab = t;
            s.length = n;
            s.index = i;

            // s.next = stack  ->  next 指向上一个 TableStack (遍历过程中遇到多次扩容)
            s.next = stack;
            // stack 指向新的 TableStack
            stack = s;
        }

        /**
         * Possibly pops traversal state.
         *
         * @param n length of current table
         */
        // 重新获取遍历状态
        private void recoverState(int n) {
            TableStack<K,V> s; int len;
            // s = stack
            // -->  index = index + s.length  <---, 大于等于n 说明超出了表的索引位置
            // n 是当前表的长度, s.length是前一个表的长度。 比如:当前表的长度n 为32,前一个表的长度s.length = 16
            // 读取的索引为 index = 3,那么使用新表读完索引3的元素后,还需要读取索引 3 + 16 的元素
            while ((s = stack) != null && (index += (len = s.length)) >= n) {
                // n 设置为上一个表的长度
                n = len;
                // index 设置为上一个表遍历的索引位置
                index = s.index;
                // tab 设置为上一个表,回到上一个表遍历
                tab = s.tab;
                s.tab = null;
                // s.next 为s 的上一个 TableStack
                TableStack<K,V> next = s.next;
                // s.next 设置为 spare (用过的TableStack使用链表的形式保存起来,
                // 遍历下一个索引的时候会一个接一个取出来使用)
                s.next = spare; // save for reuse
                // stack 设置上一个TableStack, 这个设置之后, stack 可以为 null
                stack = next;
                // 把 s 赋值给 spare,把TableStack 保存起来下次使用
                spare = s;
            }

            // s = null 才会计算  index += baseSize
            // 当初始表的下一个扩容表遍历完成之后,s才会为null。比如 初始表为 table1, 长度为16,
            // 扩容表为table2,长度为32, 遍历索引1的元素时,需要遍历table2索引1、索引17的元素,
            // table2的索引1、17元素遍历完成之后,s = null,然后开始遍历索引table1索引2的元素

            // 回到初始表遍历的时候 s才会为 null
            if (s == null && (index += baseSize) >= n)
                // baseIndex + 1,并赋值给 index
                index = ++baseIndex;
        }
    }

    /**
     * Base of key, value, and entry Iterators. Adds fields to
     * 添加字段以支持iterator.remove.
     * Traverser to support iterator.remove.
     */
    static class BaseIterator<K,V> extends Traverser<K,V> {
        final ConcurrentHashMap<K,V> map;
        Node<K,V> lastReturned;

        BaseIterator(Node<K,V>[] tab, int size, int index, int limit,
                    ConcurrentHashMap<K,V> map) {
            super(tab, size, index, limit);
            this.map = map;
            // 先调用advance()遍历出第一个元素,以支持hasNext()方法
            advance();
        }

        // 判断是否还有下个元素,接口 Iterator的方法
        public final boolean hasNext() { return next != null; }

        // 判断是否还有下个元素,接口 Enumeration的方法
        public final boolean hasMoreElements() { return next != null; }

        // 删除遍历到的元素
        public final void remove() {
            Node<K,V> p;
            // lastReturned = null,抛出异常
            if ((p = lastReturned) == null)
                throw new IllegalStateException();
            // 设置lastReturned = null
            lastReturned = null;
            // 删除节点
            map.replaceNode(p.key, null, null);
        }
    }

    // BaseIterator<K,V> extends Traverser<K,V>
    // Iterator 接口中的其他方法已经在父类BaseIterator中实现了
    static final class KeyIterator<K,V> extends BaseIterator<K,V>
        implements Iterator<K>, Enumeration<K> {

        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
                    ConcurrentHashMap<K,V> map) {
            super(tab, index, size, limit, map);
        }

        public final K next() {
            Node<K,V> p;
            // p = next, next = null,说明没有元素了
            if ((p = next) == null)
                throw new NoSuchElementException();
            // 获取key值
            K k = p.key;
            // 记录此次返回的节点,以支持删除
            lastReturned = p;
            // 获取遍历的下一个元素
            advance();
            return k;
        }

        // 直接调用next()
        public final K nextElement() { return next(); }
    }

    static final class ValueIterator<K,V> extends BaseIterator<K,V>
        implements Iterator<V>, Enumeration<V> {

        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
                      ConcurrentHashMap<K,V> map) {
            super(tab, index, size, limit, map);
        }

        public final V next() {
            Node<K,V> p;
            // p = next,next = null,说明没有元素了,抛出异常
            if ((p = next) == null)
                throw new NoSuchElementException();
            // 获取value 值
            V v = p.val;
            // 记录此次返回的节点,以支持删除
            lastReturned = p;
            // 获取遍历的下一个元素
            advance();
            return v;
        }

        // Enumeration接口的方法
        public final V nextElement() { return next(); }
    }

    static final class EntryIterator<K,V> extends BaseIterator<K,V>
        implements Iterator<Map.Entry<K,V>> {

        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
                      ConcurrentHashMap<K,V> map) {
            super(tab, index, size, limit, map);
        }

        public final Map.Entry<K,V> next() {
            Node<K,V> p;
            // p = next, next = null,说明没有元素了
            if ((p = next) == null)
                throw new NoSuchElementException();
            // 获取 key和 value
            K k = p.key;
            V v = p.val;
            // 记录此次返回的节点,以支持删除
            lastReturned = p;
            // 获取遍历的下一个元素
            advance();

            // 创建Entry节点,传入map以支持value的修改
            // HashMap直接返回Node,这两个map的Node节点都有实现 Map.Entry<K,V>接口,
            // 但是ConcurrentHashMap的Node不支持value的修改,需要通过 map.put(key, value)
            // 方法进行修改,因为ConcurrentHashMap的更新操作需要获取锁
            return new MapEntry<K,V>(k, v, map);
        }
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值