ConcurrentHashMap jdk1.8源码详解

原理:cas + synchronized + 数组 + 链表 + 红黑树

属性:

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable {
    
    // hash表的最大容量
     private static final int MAXIMUM_CAPACITY = 1 << 30;

    // hash表的初始容量
    private static final int DEFAULT_CAPACITY = 16;

    // 最大数组长度,可能在toArray()相关方法中用到
    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    // 默认并发级别 jdk1.7 之前遗留的 1.8只用于初始化,没有使用,后续版本会移除掉
    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

    // 负载因子
    private static final float LOAD_FACTOR = 0.75f;

    // 链表树化条件,即hash表冲突链表的元素 > 8,会作为链表转红黑树的一个条件
    static final int TREEIFY_THRESHOLD = 8;

    // 取消树化条件
    static final int UNTREEIFY_THRESHOLD = 6;

    // hash表树化的最小节点容量,即只有hash表的长度 > 64 && 链表长度 > 8 才会将链表转为红黑树,否则只是resize扩容hash表
    static final int MIN_TREEIFY_CAPACITY = 64;

    // 线程迁移数据最小步长 控制线程迁移任务最小区间的一个值
    private static final int MIN_TRANSFER_STRIDE = 16;

    //  扩容用  计算扩容生成一个标识戳
    private static int  = 16;

    // 65535 标识并发扩容最大线程数量
    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;

    // 扩容相关
    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;

    // node 结点的hash 是-1 表示 当前结点是forwardingNode结点
    /**
    ForwardingNode是一种临时节点,在扩容进行中才会出现,并且它不存储实际的数据。
	如果旧数组的一个hash桶中全部的节点都迁移到新数组中,旧数组就在这个hash桶中放置一个ForwardingNode.
	读操作或者迭代读时碰到ForwardingNode时,将操作转发到扩容后的新的table数组上去执行,写操作碰见它时,则尝试帮助扩容。
    */
    static final int MOVED     = -1; // hash for forwarding nodes
    
    // 红黑树的代理结点
    /**
    TreeBin是ConcurrentHashMap中用于代理操作TreeNode的特殊节点,持有存储实际数据的红黑树的根节点。
	因为红黑树进行写入操作,整个树的结构可能会有很大的变化,这个对读线程有很大的影响,所以TreeBin还要维护一个简单读写锁,
	这是相对HashMap,这个类新引入这种特殊节点的重要原因。
    */
    static final int TREEBIN   = -2; // hash for roots of trees
    
    // 代表当前节点是一个保留节点,即占位符
    static final int RESERVED  = -3; // hash for transient reservations
    
    // 0x7fffffff = 31个1  用于将一个负数变成一个正数 但是不是取绝对值
    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash

    // 系统cpu数量
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    // 用于序列化兼容
    private static final ObjectStreamField[] serialPersistentFields = {
        new ObjectStreamField("segments", Segment[].class),
        new ObjectStreamField("segmentMask", Integer.TYPE),
        new ObjectStreamField("segmentShift", Integer.TYPE)
    };
    
    
    
    // hash表
    transient volatile Node<K,V>[] table;

    // 扩容时用的hash表
    private transient volatile Node<K,V>[] nextTable;

    // baseCount属性是在没有争用现象时的基本计数器值,也在初始化表的竞争中使用。
    private transient volatile long baseCount;

    /**
    sizeCtl < 0 
        1. -1 的时候 表示table正在初始化(有线程正在初始化, 当前线程应该自旋等待)
        2. 其他情况 表示当前map正在进行扩容 高16位表示 扩容的标识戳, 低16位表示 扩容线程数量
    sizeCtl = 0 
        表示创建数组 使用默认容量 16     表示没有初始化
    sizeCtl > 0
        1. 如果table 未初始化 表示 初始化大小    putAll方法
        2. 如果table 已经初始化 表示下次扩容的阈值  
    */
    private transient volatile int sizeCtl;

    //扩容过程中,记录当前进度,所有线程都需要从transferIndex中分配区间任务,去执行自己的任务
    private transient volatile int transferIndex;

    // 0:表示无锁 1:表示加锁
    private transient volatile int cellsBusy;

    // LongAdder 中的cells 数组 当baseCount发生竞争后 会创建cells 数组
 	// 线程会通过计算hash值 取到自己的cell中
    private transient volatile CounterCell[] counterCells;

    // views
    private transient KeySetView<K,V> keySet;
    private transient ValuesView<K,V> values;
    private transient EntrySetView<K,V> entrySet;
}

内部类:

Node链表节点:
static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;  //节点hash值
    final K key;     // key
    volatile V val;  // value
    volatile Node<K,V> next;  // 下一个节点的值

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

    public final K getKey()       { return key; }
    public final V getValue()     { return val; }
    public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
    public final String toString(){ return key + "=" + val; }
    public final V setValue(V value) {
        throw new UnsupportedOperationException();
    }

    public final boolean equals(Object o) {
        Object k, v, u; Map.Entry<?,?> e;
        return ((o instanceof Map.Entry) &&
                (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
                (v = e.getValue()) != null &&
                (k == key || k.equals(key)) &&
                (v == (u = val) || v.equals(u)));
    }

    // 支持get方法,在子类中被覆盖使用
    Node<K,V> find(int h, Object k) {
        Node<K,V> e = this;
        if (k != null) {
            do {
                K ek;
                if (e.hash == h &&
                    ((ek = e.key) == k || (ek != null && k.equals(ek))))
                    return e;
            } while ((e = e.next) != null);
        }
        return null;
    }
}
ForwardingNode节点:

用来标识旧hash表扩容后占位的临时节点,即当前桶扩容迁移成功的标识

static final class ForwardingNode<K,V> extends Node<K,V> {
    final Node<K,V>[] nextTable; // 扩容引用,即新的hash表
    ForwardingNode(Node<K,V>[] tab) {
        super(MOVED, null, null, null);
        this.nextTable = tab;
    }

    Node<K,V> find(int h, Object k) {
            // 自旋
            // outer:最外层的循环标签
            /*
             * tab一定不为null
             * 整个ConcurrentHashMap源码中,只有一个地方实例化ForwardingNode,
             * 就是在transfer迁移数据方法中执行了:ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
             * 将新表赋值给tab
             */
            outer: for (Node<K,V>[] tab = nextTable;;) {
                /*
                * e 表示新表中寻址算法得到的桶位头结点
                * n 表示新表的长度 
                */
                Node<K,V> e; int n;
                /*
                 * 条件1 2 3 永远不成立
                 * 条件4:在新扩容表中 重新定位 hash 对应的头结点
                 *   true -> 1.在oldTable中 对应的桶位在迁移之前就是null
                 *           2.扩容完成后,有其它写线程,将此桶位设置为了null
                 */
                if (k == null || tab == null || (n = tab.length) == 0 ||
                    (e = tabAt(tab, (n - 1) & h)) == null)
                    return null; // 新表桶位没有数据 直接返回null
                /*
                 * 前置条件:扩容后的表,对应hash的桶位不是null,e为此桶位的头结点
                 * e可能是哪些类型?
                 *   1.node类型
                 *   2.TreeBin类型
                 *   3.FWD类型(高并发下扩容后再次触发扩容)
                 */
                // 自旋
                for (;;) {
                    /*
                     * eh:新扩容后表指定桶位的当前节点的hash 
                     * ek:新扩容后表指定桶位的当前节点的key
                     */
                    int eh; K ek; 
                    // 当前桶位查找成功
                    if ((eh = e.hash) == h &&
                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                    /*
                     * eh < 0
                     *   1.可能是TreeBin节点
                     *   2.可能是FWD节点(新扩容后的表,可能在并发很大的情况下,再次扩容) 
                     */
                    if (eh < 0) {
                        // fwd节点 继续进行外层循环,继续在新表中查找
                        if (e instanceof ForwardingNode) {
                            // 在新的fwd节点中拿到更新的表
                            tab = ((ForwardingNode<K,V>)e).nextTable;
                            continue outer; // 从最外层循环开始执行
                        }
                        // 说明此桶位为TreeBin节点,使用TreeBin.find()查找红黑树中相应节点
                        else
                            return e.find(h, k);
                    }
                    // 此处桶位是链表,遍历到链表末尾也没有找到目标节点,返回null
                    if ((e = e.next) == null)
                        return null;
                }
            }
        }
    }
}

 //tabAt()方法可以获得在 i 位置上的 Node 节点。
 static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
     return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
 }
TreeNode节点:
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;
    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);
    }

    /**
         * 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<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)
                    p = pl;
                else if (ph < h)
                    p = pr;
                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                    return p;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.findTreeNode(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
        }
        return null;
    }
}
TreeBin节点:
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
        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);
            this.first = b;
            TreeNode<K,V> r = null;
            for (TreeNode<K,V> x = b, next; x != null; x = next) {
                next = (TreeNode<K,V>)x.next;
                x.left = x.right = null;
                if (r == null) {
                    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;;) {
                        int dir, ph;
                        K pk = p.key;
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                            dir = 1;
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);
                            TreeNode<K,V> xp = p;
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            r = balanceInsertion(r, x);
                            break;
                        }
                    }
                }
            }
            this.root = r;
            assert checkInvariants(root);
        }

        /**
         * Acquires write lock for tree restructuring.
         */
        private final void lockRoot() {
            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
                contendedLock(); // offload to separate method
        }

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

        /**
         * Possibly blocks awaiting root lock.
         */
        private final void contendedLock() {
            boolean waiting = false;
            for (int s;;) {
                if (((s = lockState) & ~WAITER) == 0) {
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
                        if (waiting)
                            waiter = null;
                        return;
                    }
                }
                else if ((s & WAITER) == 0) {
                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
                        waiting = true;
                        waiter = Thread.currentThread();
                    }
                }
                else if (waiting)
                    LockSupport.park(this);
            }
        }

        /**
         * 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;
                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
                        if (e.hash == h &&
                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
                            return e;
                        e = e.next;
                    }
                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
                                                 s + READER)) {
                        TreeNode<K,V> r, p;
                        try {
                            p = ((r = root) == null ? null :
                                 r.findTreeNode(h, k, null));
                        } finally {
                            Thread w;
                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
                                (READER|WAITER) && (w = waiter) != null)
                                LockSupport.unpark(w);
                        }
                        return p;
                    }
                }
            }
            return null;
        }

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

                TreeNode<K,V> xp = p;
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    TreeNode<K,V> x, f = first;
                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
                    if (f != null)
                        f.prev = x;
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    if (!xp.red)
                        x.red = true;
                    else {
                        lockRoot();
                        try {
                            root = balanceInsertion(root, x);
                        } finally {
                            unlockRoot();
                        }
                    }
                    break;
                }
            }
            assert checkInvariants(root);
            return null;
        }

        /**
         * Removes the given node, that must be present before this
         * 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.
         *
         * @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)
                first = next;
            else
                pred.next = next;
            if (next != null)
                next.prev = pred;
            if (first == null) {
                root = null;
                return true;
            }
            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;
                if (pl != null && pr != null) {
                    TreeNode<K,V> s = pr, sl;
                    while ((sl = s.left) != null) // find successor
                        s = sl;
                    boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                    TreeNode<K,V> sr = s.right;
                    TreeNode<K,V> pp = p.parent;
                    if (s == pr) { // p was s's direct parent
                        p.parent = s;
                        s.right = p;
                    }
                    else {
                        TreeNode<K,V> sp = s.parent;
                        if ((p.parent = sp) != null) {
                            if (s == sp.left)
                                sp.left = p;
                            else
                                sp.right = p;
                        }
                        if ((s.right = pr) != null)
                            pr.parent = s;
                    }
                    p.left = null;
                    if ((p.right = sr) != null)
                        sr.parent = p;
                    if ((s.left = pl) != null)
                        pl.parent = s;
                    if ((s.parent = pp) == null)
                        r = s;
                    else if (p == pp.left)
                        pp.left = s;
                    else
                        pp.right = s;
                    if (sr != null)
                        replacement = sr;
                    else
                        replacement = p;
                }
                else if (pl != null)
                    replacement = pl;
                else if (pr != null)
                    replacement = pr;
                else
                    replacement = p;
                if (replacement != p) {
                    TreeNode<K,V> pp = replacement.parent = p.parent;
                    if (pp == null)
                        r = replacement;
                    else if (p == pp.left)
                        pp.left = replacement;
                    else
                        pp.right = replacement;
                    p.left = p.right = p.parent = null;
                }

                root = (p.red) ? r : balanceDeletion(r, replacement);

                if (p == replacement) {  // detach pointers
                    TreeNode<K,V> pp;
                    if ((pp = p.parent) != null) {
                        if (p == pp.left)
                            pp.left = null;
                        else if (p == pp.right)
                            pp.right = null;
                        p.parent = null;
                    }
                }
            } finally {
                unlockRoot();
            }
            assert checkInvariants(root);
            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)
                    rl.parent = p;
                if ((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                else if (pp.left == p)
                    pp.left = r;
                else
                    pp.right = 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) {
                if ((lr = p.left = l.right) != null)
                    lr.parent = p;
                if ((pp = l.parent = p.parent) == null)
                    (root = l).red = false;
                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.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null)
                    return root;
                if (xp == (xppl = xpp.left)) {
                    if ((xppr = xpp.right) != null && xppr.red) {
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                else {
                    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);
                            }
                        }
                    }
                }
            }
        }

        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
                                                   TreeNode<K,V> x) {
            for (TreeNode<K,V> xp, xpl, xpr;;)  {
                if (x == null || x == root)
                    return root;
                else if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (x.red) {
                    x.red = false;
                    return root;
                }
                else if ((xpl = xp.left) == x) {
                    if ((xpr = xp.right) != null && xpr.red) {
                        xpr.red = false;
                        xp.red = true;
                        root = rotateLeft(root, xp);
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }
                    if (xpr == null)
                        x = xp;
                    else {
                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
                        if ((sr == null || !sr.red) &&
                            (sl == null || !sl.red)) {
                            xpr.red = true;
                            x = xp;
                        }
                        else {
                            if (sr == null || !sr.red) {
                                if (sl != null)
                                    sl.red = false;
                                xpr.red = true;
                                root = rotateRight(root, xpr);
                                xpr = (xp = x.parent) == null ?
                                    null : xp.right;
                            }
                            if (xpr != null) {
                                xpr.red = (xp == null) ? false : xp.red;
                                if ((sr = xpr.right) != null)
                                    sr.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateLeft(root, xp);
                            }
                            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;
            if (tb != null && tb.next != t)
                return false;
            if (tn != null && tn.prev != t)
                return false;
            if (tp != null && t != tp.left && t != tp.right)
                return false;
            if (tl != null && (tl.parent != t || tl.hash > t.hash))
                return false;
            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);
            }
        }
    }

put方法

// 添加元素
public V put(K key, V value) {
   return putVal(key, value, false);
}

// onlyIfAbsent --> ture:表示如果遇到相同的key 进行不进行置换    false:表示替换
final V putVal(K key, V value, boolean onlyIfAbsent) {
	// key && value 都不能是null
    if (key == null || value == null) throw new NullPointerException();
    // 通过扰动函数 计算出新的hash 高16位也参与运算
    int hash = spread(key.hashCode());
    //  binCount:表示当前k-v 封装成node 后插入到指定桶位后 在桶位中所属链表的下标位置
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {// 自旋过程
    	/*
    	f ->头结点 n->代表table的长度 i->索引 
    	fh->头结点hash fk->头结点的key  fv->头结点的value
    	*/
        Node<K,V> f; int n, i, fh; K fk; V fv;
        // hash表没有创建,则进行初始化
        if (tab == null || (n = tab.length) == 0){
            tab = initTable();
            
		// tabAt(tab,i =(n-1)&hash) 得到头结点 
		// 判断头结点是不是为空  前置条件 表已经创建
        }else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
        	// cas成功 如果头结点是空 直接用cas 的操作 尝试用new的结点替换 头结点 
        	// cas失败 说明其他线程已经插入了 需要自旋 继续操作
            if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
                break;                  
        }
        
        // 前置条件 表已经创建 && 头结点不是空 
        // 判断头结点的hash 是不是等于-1  看是不是forwardingNode结点 如果是 说明哈希表正在处于扩容的情况,则帮助扩容
        else if ((fh = f.hash) == MOVED){
        	// 当前线程帮忙扩容 
            tab = helpTransfer(tab, f);
            
         // 前置条件 表已经创建 && 头结点不是空 && 不处于扩容中
         // 头结点是key相同的结点 并且不支持替换 就直接返回当前结点的值
        }else if (onlyIfAbsent 
                 && fh == hash
                 && ((fk = f.key) == key || (fk != null && key.equals(fk)))
                 && (fv = f.val) != null){
            return fv;
            
        //  前置条件 表已经创建 && 头结点不是空 && 不处于扩容中 && 头结点不是key相同的结点
        }else { 
    		// 用于记录旧的value
            V oldVal = null;
            //  锁住头结点
            synchronized (f) {
            	// 再次查询头结点是不是等于f 
            	// 防止你加锁的过程中 别人已经修改了头结点的值,导致操作出现问题
                if (tabAt(tab, i) == f) {
                	// 前置条件 头结点没有改变
                	// 判断头结点 是不是普通链表 fh>0
                    if (fh >= 0) {
                    	// 当前列表的末尾,bincount表示链表的长度
                        //2 : 当前插入的key 与链表的某个元素key 一样 当前插入操作表示冲突位置 (binCount-1)
                        binCount = 1;
                        // 遍历链表
                        for (Node<K,V> e = f;; ++binCount) {
                            K ek; // 迭代遍历结点的key
                            if (e.hash == hash && // 找到了key相同的结点
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                oldVal = e.val;// 保留老的值
                                if (!onlyIfAbsent)
                                    e.val = value;// 更新value
                                break;
                            }
                            // 记录用pred记录上一个结点
                            Node<K,V> pred = e;
                            // 判断next 是不是为空
                            if ((e = e.next) == null) {
                            // 没有key相同的结点 就 插入在末尾
                                pred.next = new Node<K,V>(hash, key, value);
                                break;
                            }
                        }
                    }
                    // fh<0 说明是Treebin
                    else if (f instanceof TreeBin) {
                        Node<K,V> p;
                        binCount = 2;
                        if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                       value)) != null) {
                            oldVal = p.val;
                            if (!onlyIfAbsent)
                                p.val = value;
                        }
                    }
                    else if (f instanceof ReservationNode)
                        throw new IllegalStateException("Recursive update");
                }
            }
            // 当前桶位不是 null  是红黑树 或者 链表
            if (binCount != 0) {
           		// 是不是需要树化
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null) // key 有没有相同的 发生冲突的情况
                    return oldVal;
                break;
            }
        }
        
    } //自旋结束
    
    //  统计table 一共有多少数据
    // 是不是需要扩容
    addCount(1L, binCount);
    return null;
}


// 扰动函数,高16位也参与hash运算,目的减少hash冲突
// &HASH_BITS的作用:保证这个数是正数,负数有特殊的含义
static final int spread(int h) {
    return (h ^ (h >>> 16)) & HASH_BITS;
}

// 初始化hash表
private final Node<K,V>[] initTable() {
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
        // sizeCtrl < 0:表示其他线程正在初始化或者扩容,则让出cpu
        if ((sc = sizeCtl) < 0)
            Thread.yield(); // lost initialization race; just spin
        
        // 否则使用cas将sizeCtrl设置为-1,表示正在初始化
        else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
            try {
                // 再次判断,防止重复初始化,
                // 当一个线程走到sc = n - (n >>> 2);这一步时,其他线程可以走到当前代码块。为了不重复走初始化的逻辑,所以要再次判断
                if ((tab = table) == null || tab.length == 0) {
                    
                    // 获取hash表长度,sizeCtrl > 0则把sizeCtrl作为hash的长度,否则使用默认值16作为初始化长度
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    // 创建hash表,以n的长度
                    @SuppressWarnings("unchecked")
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    // 初始化完成table
                    table = tab = nt;
                    // 已经初始化完成,则sizeCtrl表示下次扩容时的阈值,所以这里计算的是阈值,比如最开始sc = 16 * 0.75 = 12
                    sc = n - (n >>> 2);
                }
            } finally {
                // 将sc赋值给sizeCtrl
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}

// cas在hash表的i位置设置值
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                    Node<K,V> c, Node<K,V> v) {
    return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}


treeifyBin方法:

// 树化
private final void treeifyBin(Node<K,V>[] tab, int index) {
    Node<K,V> b; int n, sc;
    if (tab != null) {
        // hash表长度 < 64
        if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
            // 尝试扩容,n左移1位,相当于乘2
            tryPresize(n << 1);
        // hash表长度 > 64,则转红黑树
        else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
            synchronized (b) {
                if (tabAt(tab, index) == b) {
                    TreeNode<K,V> hd = null, tl = null;
                    // 将Node节点转为TreeNode节点
                    for (Node<K,V> e = b; e != null; e = e.next) {
                        TreeNode<K,V> p =
                            new TreeNode<K,V>(e.hash, e.key, e.val,
                                              null, null);
                        if ((p.prev = tl) == null)
                            hd = p;
                        else
                            tl.next = p;
                        tl = p;
                    }
                    // new TreeBin构造函数会做转红黑树的操作,然后设置为index位置
                    setTabAt(tab, index, new TreeBin<K,V>(hd));
                }
            }
        }
    }
}

tryPresize方法:

private final void tryPresize(int size) {
    // 扩容size如果大于最大值,则取最大值即可,否则tableSizeFor进行向上取2的次方
    int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
    tableSizeFor(size + (size >>> 1) + 1);
    int sc;
    // 1.没有初始化  2.已经初始化
    while ((sc = sizeCtl) >= 0) {
        Node<K,V>[] tab = table; int n;
        //1.没有初始化,则进行初始化
        // 初始化代码片段,同initTable类似, 如果hash表没有初始化,则进行初始化
        if (tab == null || (n = tab.length) == 0) {
            // n = max(原来的容量sc,扩容的容量c)
            n = (sc > c) ? sc : c;
            if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                    if (table == tab) {
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = nt;
                        sc = n - (n >>> 2);
                    }
                } finally {
                    sizeCtl = sc;
                }
            }
        }
        //2.已经初始化,扩容
        // 扩容长度 < 扩容的阈值,说明已经扩容完了,直接退出,不需要管
        // 数组长度大于最大值了,无需扩容
        else if (c <= sc || n >= MAXIMUM_CAPACITY)
            break;
        // 开始扩容
        else if (tab == table) {
            // 得到一个扩容戳(长度为32位,高16位作扩容标识,低16位作扩容线程数)
            int rs = resizeStamp(n);
            // 表示其他线程正在扩容,帮助扩容
            if (sc < 0) {
                Node<K,V>[] nt;
                // 迁移结束,则break
                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);
            }
            // 否则当前线程自己扩容
            else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                         (rs << RESIZE_STAMP_SHIFT) + 2))
                transfer(tab, null);
        }
    }
}

addCount方法

private final void addCount(long x, int check) {
    //cs 是cells 单元
    //b 是未发生竞争的base
    // s 是元素数量
    CounterCell[] cs; long b, s;
    // LongAdder 操作   
    if ((cs = counterCells) != null ||
        !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
        CounterCell c; long v; int m;
        boolean uncontended = true;
        if (cs == null || (m = cs.length - 1) < 0 ||
            (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
            !(uncontended =
              U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
            fullAddCount(x, uncontended);
            return;
        }
        if (check <= 1)
            return;
        //【以线程安全的方式计算concurrentHashMap元素个数】
        s = sumCount();
    }
    
    // 【检查扩容】
    // 如果check >=0 说明一定是put 调用的 addCount
    if (check >= 0) {
        // tab  表示 map.table
        // nt 是nexttable
        // n 是数组长度
        // sc 是sizeCtl的长度
        Node<K,V>[] tab, nt; int n, sc;
        // 自旋
        // 条件1  s >= (long)(sc = sizeCtl)
        // ture 1: 当前sizeCtl 是一个负数 表示正在扩容中。
        //      2: 当前sizeCtl 是一个正数 表示扩容阈值
        // false  表示当前table 尚未达到扩容条件
        // 条件2:(tab = table) != null  hash表是否初始化
        // 条件3: 当前table长度小于最大值限制 可以扩容
        while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
               (n = tab.length) < MAXIMUM_CAPACITY) {
            // 获取到唯一标识戳
            int rs = resizeStamp(n);
            // 条件1
            // ture 说明当前线程获取的扩容唯一标识撮 不是本次扩容
            // false 说明当前线程获取到的扩容唯一标识撮 是本次扩容
            // 条件2
            // ture 表示扩容完毕了 false 表示在扩容过程中
            // 条件3
            // ture : 触发的帮助扩容的达到最大值 65535-1
            // false 可以参与
            // 条件4
            // ture 扩容结束
            // false 扩容正在进行
            if (sc < 0) {
                // 迁移成功则直接break
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                    transferIndex <= 0)
                    break;
                // 当前线程正在扩容中 当前线程参与
                // ture 可以参与
                //fasle 进行自旋 大概率还会来到这里
                //条件失败 1 当前有很多线程都尝试修改sizeCtl 可能会导致和内存的不一样
                // transfer 任务内的线程也修改sizeCtl
                // 帮助扩容
                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
                    // 协助扩容线程 支持nextTable参数
                    transfer(tab, nt);
            }
            // 条件成立 说明当前线程是触发扩容的第一个线程 在transfer方法需要做一些扩容的准备工作
            else if (U.compareAndSetInt(this, SIZECTL, sc,
                                        (rs << RESIZE_STAMP_SHIFT) + 2))
                //触发扩容的线程 不持有nextTable
                transfer(tab, null);
            s = sumCount();
        }
    }
}

helpTransfer方法:

// 协助扩容
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
    // nextTable 就是fwd.nextTable
    Node<K,V>[] nextTab; int sc;
    //条件三:
    // 恒成立
    if (tab != null && (f instanceof ForwardingNode) &&
        (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {

        // 拿当前表的长度 获取扩容标识戳
        int rs = resizeStamp(tab.length);
        // 条件1 :
        // 成立 标识当前扩容正在执行
        //不成立 1. nextTable被设置为null 已经扩容完毕了
        //      2。 再次出发扩容了 nextTable 已经过期了
        //条件2 成立 说明扩容正在进行
        // 不成立 扩容结束了 扩容结束之后最后退出的线程会把nextTable设置为table
        // 条件3: 扩容正在进行中
        //  不成立 sizeCtl 是当前扩容阈值 扩容已经结束了
        while (nextTab == nextTable && table == tab &&
               (sc = sizeCtl) < 0) {
            //当前线程没事干了 直接不进入
            if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                sc == rs + MAX_RESIZERS || transferIndex <= 0)
                break;
            // 尝试增加一个线程 帮助扩容
            if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
                transfer(tab, nextTab);
                break;
            }
        }
        return nextTab;
    }
    return table;
}

transfer方法:

// transfer方法用于将元素从旧的数组迁移到新的数组中
// 参数advance表示是否继续迁移元素
// tab:旧hash表   nextTab:新的hash表,不为null:表示帮助扩容  null:表示自己扩容
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
    // n:扩容之前table数组的长度  tride:分配给线程任务的步长,即每个线程迁移的数据范围
    int n = tab.length, stride;
    // 结合cpu核心数计算每个线程要迁移的数据大小
    if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
        stride = MIN_TRANSFER_STRIDE; // 每个线程最小的迁移数量为16
    // nextTab为空,说明是第一次扩容,需要创建一个新的hash表
    if (nextTab == null) {
        try {
            // 创建了比扩容之前大1倍的table
            @SuppressWarnings("unchecked")
            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
            nextTab = nt;
        } catch (Throwable ex) {      // try to cope with OOME
            sizeCtl = Integer.MAX_VALUE;
            return;
        }
        nextTable = nextTab; // 方便协助线程 拿到新表
        transferIndex = n;// 记录迁移数据整体位置的一个标记 从1开始
    }
    // 新表长度
    int nextn = nextTab.length;
    // 新表的引用 当某个桶位处理完毕 将设置为fwd 结点
    ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
    boolean advance = true;// 推进标记,标识是否继续迁移元素
    boolean finishing = false; // 完成标记
    // i 表示分配给当前线程任务,执行到的桶位
    // bound 表示分配给当前线程的下界限制
    int i = 0, bound = 0;
    for (;;) {// 自旋
        // f 桶位的头结点 fh 头结点的hash
        Node<K,V> f; int fh;
        /**
          * 1 给当前线程分配区间
          * 2 维护当前线程任务进度(i 当前处理的桶位
          * 3 维护map对象全局范围内的进度
          */
        while (advance) {
            // 分配任务区间的变量 nextIndex分配开始的下标 nextBound 结束下标
            int nextIndex, nextBound;
            //  --i>=bound 当前线程任务尚未完成, 还有相应的区间桶位要处理 --i 表示下一个处理的桶位
            // 不成立 表示已经完成 或者未分配
            // i:表示当前线程在迁移自己范围的数组下标元素t[i]
            if (--i >= bound || finishing)
                advance = false;
            // 前置条件 任务已经完成 或者还没有分配任务
            // 条件成立 表示对象全局范围内的桶位都分配完毕了 没有区间分配了
            // 设置全局i变量为-1 执行退出迁移相关的程序
            // 不成立 全局范围内的桶位尚未分配还有区间可分配
            // transferIndex:表示每个线程分配的一段迁移范围的起始下标,比如数组长度32,则第一个线程的transferIndex=16,第二个线程的transferIndex=0
            else if ((nextIndex = transferIndex) <= 0) {
                i = -1;
                advance = false;
            }
            // 前置条件 当前线程需要分配任务区间 2 【全局范围内的桶位尚未分配还有区间可分配】
            // 条件成功 说明给当前任务分配成功
            // 失败 就是 说明分配给当前线程失败,可能发生竞争
            else if (U.compareAndSetInt
                     (this, TRANSFERINDEX, nextIndex,
                      nextBound = (nextIndex > stride ?
                                   nextIndex - stride : 0))) {
                // 区间复制给bound
                bound = nextBound;
                // 【transferIndex,transferIndex+n】区间结尾-1
                i = nextIndex - 1;
                advance = false; // 结束
            }
        }

        // i<0 的情况 表示当前线程未分配到任务,或任务结束
        if (i < 0 || i >= n || i + n >= nextn) {
            int sc;// sizeCtl 的临时变量
            
            // finishing = true:扩容结束
            if (finishing) {
                nextTable = null;
                table = nextTab;
                sizeCtl = (n << 1) - (n >>> 1);
                return;
            }
            //  迁移退出一个线程
            //  条件成立 说明 设置sizeCtl 低16位-1成功 当前线程可以退出
            if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                //条件成立 说明当前线程不是最后一个退出transfer任务线程
                if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                    // 最后一个线程退出,则return
                    return;
                finishing = advance = true;
                i = n; // recheck before commit
            }
        }
        //前置条件
        //casr1:成立:说明当前桶没有存放数据 只需要将此处设置为fwd结点
        else if ((f = tabAt(tab, i)) == null)
            advance = casTabAt(tab, i, null, fwd);
        //casr2:条件成立 说明当前桶位已经迁移过了,当前线程不用再处理
        // 直接在此更新当前线程任务索引,在处理下一个桶位。
        else if ((fh = f.hash) == MOVED)
            advance = true; // already processed
        // 前置条件 当前桶位有数据 而且node结点不是fwd结点 说明这些数据需要迁移
        else {
            // sync 加锁当前桶位的头结点
            synchronized (f) {
                // 防止 在你加锁投之前 头对象被其他线程修改过 导致你加锁对象错误
                if (tabAt(tab, i) == f) {
                    // ln 低位链表 hn 高位链表
                    Node<K,V> ln, hn;
                    if (fh >= 0) { // 条件成立表示当前桶位是链表

                        //lastRun
                        // 可以获取当前链表 末尾连续高位不变的 node
                        int runBit = fh & n;
                        Node<K,V> lastRun = f;
                        for (Node<K,V> p = f.next; p != null; p = p.next) {
                            int b = p.hash & n;
                            if (b != runBit) {
                                runBit = b;
                                lastRun = p;
                            }
                        }
                        // 说明 lastRun链表 为低位链表 让ln 引用lastRun
                        if (runBit == 0) {
                            ln = lastRun;
                            hn = null;
                        }
                        else {
                            hn = lastRun;
                            ln = null;
                        }
                        //迭代链表 当循环结点 不等于lastRun
                        for (Node<K,V> p = f; p != lastRun; p = p.next) {
                            int ph = p.hash; K pk = p.key; V pv = p.val;
                            if ((ph & n) == 0)
                                ln = new Node<K,V>(ph, pk, pv, ln);
                            else
                                hn = new Node<K,V>(ph, pk, pv, hn);
                        }
                 
                        // 将ln低位节点设置到新链表nextTab的【原旧链表下标i】位置
                        setTabAt(nextTab, i, ln);
                        // 将hn高位节点设置到新链表nextTab的【原旧链表下标i+旧链表长度】位置,这里的设置很巧妙,刚好==hash&(n-1)
                        setTabAt(nextTab, i + n, hn);
                        // 将旧链表tab的下标i设置fwd元素,表示当前元素迁移完成
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                    // 当前要迁移的节点为红黑树节点,相同的操作,遍历红黑树找出低位和高位节点,然后链接到新hash表中
                    else if (f instanceof TreeBin) {
                        // 转换头结点为treeBin 引用
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        // 低位双向链表+
                        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) {
                                if ((p.prev = loTail) == null)
                                    lo = p;
                                else
                                    loTail.next = p;
                                loTail = p;
                                ++lc;
                            }
                            else {
                                if ((p.prev = hiTail) == null)
                                    hi = p;
                                else
                                    hiTail.next = p;
                                hiTail = p;
                                ++hc;
                            }
                        }
                        ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                        (hc != 0) ? new TreeBin<K,V>(lo) : t;
                        hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                        (lc != 0) ? new TreeBin<K,V>(hi) : t;
                        setTabAt(nextTab, i, ln);
                        setTabAt(nextTab, i + n, hn);
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                }
            }
        }
    }
}

get方法:

public V get(Object key) {
    // tab 引用map.table
    // e 当前元素
    // p 目标结点
    // n 长度
    // eh 当前元素的hash
    // ek 当前元素的key
    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    int h = spread(key.hashCode());// 通过扰动运算后得到 更散列的hash值
    // 表已经创建了 而且头结点不等于null
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (e = tabAt(tab, (n - 1) & h)) != null) {
        // 头结点直接找到
        if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
        }
        // -1 fwd结点说明table正在扩容 且当前查询的已经被迁移走了
        // -2 Treebin 需要使用Treebin方法查询
        else if (eh < 0)
            return (p = e.find(h, key)) != null ? p.val : null;
        while ((e = e.next) != null) {// 链表情况
            if (e.hash == h &&
                ((ek = e.key) == key || (ek != null && key.equals(ek))))
                return e.val;
        }
    }
    return null;
}

remove方法:

public V remove(Object key) {
    return replaceNode(key, null, null);
}

final V replaceNode(Object key, V value, Object cv) {
    int hash = spread(key.hashCode());
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        if (tab == null || (n = tab.length) == 0 ||
            (f = tabAt(tab, i = (n - 1) & hash)) == null)
            break;
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            V oldVal = null;
            boolean validated = false;
            synchronized (f) {
                if (tabAt(tab, i) == f) {
                    if (fh >= 0) {
                        validated = true;
                        for (Node<K,V> e = f, pred = null;;) {
                            K ek;
                            if (e.hash == hash &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                V ev = e.val;
                                if (cv == null || cv == ev ||
                                    (ev != null && cv.equals(ev))) {
                                    oldVal = ev;
                                    if (value != null)
                                        e.val = value;
                                    else if (pred != null)
                                        pred.next = e.next;
                                    else
                                        setTabAt(tab, i, e.next);
                                }
                                break;
                            }
                            pred = e;
                            if ((e = e.next) == null)
                                break;
                        }
                    }
                    else if (f instanceof TreeBin) {
                        validated = true;
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> r, p;
                        if ((r = t.root) != null &&
                            (p = r.findTreeNode(hash, key, null)) != null) {
                            V pv = p.val;
                            if (cv == null || cv == pv ||
                                (pv != null && cv.equals(pv))) {
                                oldVal = pv;
                                if (value != null)
                                    p.val = value;
                                else if (t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                    else if (f instanceof ReservationNode)
                        throw new IllegalStateException("Recursive update");
                }
            }
            if (validated) {
                if (oldVal != null) {
                    if (value == null)
                        // 扩容,可能将红黑树转为链表
                        addCount(-1L, -1);
                    return oldVal;
                }
                break;
            }
        }
    }
    return null;
}

总结:

put总体流程:

  1. 计算key的hash值
  2. while(true):
    1. 当前hash表没有初始化,则进行初始化,continue;
    2. 当前tab[i] == null,则cas设置value,成功则break;否则continue;
    3. 当前tab[i]==fwd,说明在扩容,则帮助扩容,continue;
    4. 说明tab[i]是一个链表或者红黑树,对tab[i]加锁,进行如下操作:
      1. fh>=0,表示是一个链表节点,则遍历链表,判断key是否存在,存在则替换valule,不存在则追加;
      2. f instanceof TreeBin,表示是一个红黑树节点,则将值插入红黑树
      3. 如果是链表,则判断是否count>=8,且tab.size>=64,则树化,否则扩容;break;
  3. addCount,统计hash表的元素,支持多线程统计,原理同LongAddr类似,分段思想统计。

transfer总体流程:

  1. 计算当前线程扩容分配操作的一段区间长度stride
  2. while(true):
    1. 计算当前线程的操作区间,起始和结束下标,及维护的进度i
    2. 如果(i < 0 || i >= n || i + n >= nextn),则表示扩容结束或者当前线程没有分配到任务
      1. 判断是否迁移全局结束,结束则计算对应阈值,然后退出,break;
      2. 当前线程退出扩容,sc-1,continue;
    3. 如果oldTab[i]==null,如果当前桶迁移完毕,设置oldTab[i]=fwd,continue;
    4. fh.hash == MOVE,等价:fh==fwd,说明当前桶已经迁移完毕,continue;
    5. 进行迁移,加锁锁住桶头节点,如果是链表则进行链表迁移,如果是红黑树则进行红黑树迁移
    6. i–
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值