相较于java7中的ConcurrentHashMap,java8的实现有了较大的改变。不同于java7中采纳segment+HashEntry数组+链表构造,其采纳了Node+链表+红黑树构造。并应用了Synchronized+CAS来管制并发

put办法

public V put(K key, V value) {        return putVal(key, value, false);}  final V putVal(K key, V value, boolean onlyIfAbsent) {    if (key == null || value == null) throw new NullPointerException();    int hash = spread(key.hashCode());    // 记录链表长度    int binCount = 0;    // 进行自旋    for (Node<K,V>[] tab = table; ; ) {        // 留神这些变量所代表的含意        Node<K,V> f; int n, i, fh; K fk; V fv;        // 数组为空的状况下,进行初始化        if (tab == null || (n = tab.length) == 0)            // 初始化数组            tab = initTable();        // 找到hash值对应下标的的第一个节点         else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {            // 应用CAS,尝试将node放入。如果数组该地位是空的,那么第一次就会胜利。放入后break即可            // 如果CAS失败,则阐明有并发。持续循环进行下次操作            if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))                break;                   // no lock when adding to empty bin        }        // 这个节点正处于扩容状态        else if ((fh = f.hash) == MOVED)            tab = helpTransfer(tab, f);        // 如果onlyIfAbsent为true,判断以后存在的节点和put的值是否雷同并返回        else if (onlyIfAbsent // check first node without acquiring lock                 && fh == hash                 && ((fk = f.key) == key || (fk != null && key.equals(fk)))                 && (fv = f.val) != null)            return fv;        else {            //此时f为头节点并且不为空            V oldVal = null;            // 获取监视器锁            synchronized (f) {                if (tabAt(tab, i) == f) {                    // fh>=0,阐明是链表                    if (fh >= 0) {                        // binCount用来记录链表长度                        binCount = 1;                        // 遍历链表                        for (Node<K,V> e = f;; ++binCount) {                            K ek;                            // 如果找到了对应的key,通过onlyIfAbsent判断是否进行valuie笼罩                            // 之后就可break了                            if (e.hash == hash &&                                ((ek = e.key) == key ||                                 (ek != null && key.equals(ek)))) {                                oldVal = e.val;                                if (!onlyIfAbsent)                                    e.val = value;                                break;                            }                            Node<K,V> pred = e;                            // 没找到对应的key,就将新的node置于链表尾部                            if ((e = e.next) == null) {                                pred.next = new Node<K,V>(hash, key, value);                                break;                            }                        }                    }                    // 红黑树                    else if (f instanceof TreeBin) {                        Node<K,V> p;                        binCount = 2;                        // 应用红黑树的putTreeVal办法                        if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,                                                              value)) != null) {                            oldVal = p.val;                            if (!onlyIfAbsent)                                p.val = value;                        }                    }                    // ReservationNode是外部办法应用的节点,可疏忽                    else if (f instanceof ReservationNode)                        throw new IllegalStateException("Recursive update");                }            }                        if (binCount != 0) {                // 判断是否将链表转换为红黑树                if (binCount >= TREEIFY_THRESHOLD)                    // 此办法不肯定会进行红黑树的转换                    // 如果数组长度大于64,会抉择进行数组扩容。                    treeifyBin(tab, i);                if (oldVal != null)                    return oldVal;                break;            }        }    }    addCount(1L, binCount);    return null;} 

初始化数组initTable()

private final Node<K,V>[] initTable() {    Node<K,V>[] tab; int sc;    while ((tab = table) == null || tab.length == 0) {        if ((sc = sizeCtl) < 0)            // 到此阐明有其余线程也在尝试初始化            Thread.yield(); // lost initialization race; just spin        // CAS将sizeCtl设为-1,示意抢到了锁        else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {            try {                if ((tab = table) == null || tab.length == 0) {                    // 默认初始容量为16                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;                    @SuppressWarnings("unchecked")                    // 初始化数组                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];                    table = tab = nt;                    // 如果n为16,则sc = 0.75 * n                    sc = n - (n >>> 2);                }            } finally {                // 设置sizeCtl                sizeCtl = sc;            }            break;        }    }    return tab;} 

链表转红黑树treeifyBin

private final void treeifyBin(Node<K,V>[] tab, int index) {    Node<K,V> b; int n;    if (tab != null) {        // 如果数组长度小于64。会进行数组扩容        // 因为数组的长度都是2的幂数,所以可能会是32、16、8...等        if ((n = tab.length) < MIN_TREEIFY_CAPACITY)            tryPresize(n << 1);        // 上面代码是链表转红黑树        else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {            synchronized (b) {                if (tabAt(tab, index) == b) {                    TreeNode<K,V> hd = null, tl = null;                    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;                    }                    setTabAt(tab, index, new TreeBin<K,V>(hd));                }            }        }    }}

扩容

private final void tryPresize(int size) {    // 这个size曾经是原先的两倍了    // 判断size是否超过最大容量。若不超过则 c 为 size 的 1.5 倍,再加 1,再往上取最近的 2 的 n 次方。    int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :    tableSizeFor(size + (size >>> 1) + 1);    int sc;    while ((sc = sizeCtl) >= 0) {               Node<K,V>[] tab = table; int n;        if (tab == null || (n = tab.length) == 0) {             // 上面代码和初始化代码相似            n = (sc > c) ? sc : c;            if (U.compareAndSetInt(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;                }            }        }        //         else if (c <= sc || n >= MAXIMUM_CAPACITY)            break;        else if (tab == table) {            int rs = resizeStamp(n);            // CAS操作将sizeCtl设置为 (rs << RESIZE_STAMP_SHIFT) + 2)            if (U.compareAndSetInt(this, SIZECTL, sc,                                   (rs << RESIZE_STAMP_SHIFT) + 2))                transfer(tab, null);        }    }}

transfer办法可能会多线程调用,

private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {    // stride可了解为“步长”,其在单核下间接等于n,即原数组长度    // 在多核下,为 n>>>3/NCPU,最小值为16        // 心愿让每个CPU都尽可能解决的桶数一样多,如果桶很少,就默认一个线程解决16个桶    int n = tab.length, stride;    if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)        stride = MIN_TRANSFER_STRIDE; // subdivide range        // 如果nextTab为null,会先进行一次初始化。    // 可保障第一次个发动数据迁徙的线程调用此办法时,nextTab为null(具体可看可看此办法的调用处)    if (nextTab == null) {            // initiating        try {            @SuppressWarnings("unchecked")            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];            nextTab = nt;        } catch (Throwable ex) {      // try to cope with OOME            sizeCtl = Integer.MAX_VALUE;            return;        }        // nextTable和transferIndex都是concurrentmap中的属性        nextTable = nextTab;        transferIndex = n;    }        int nextn = nextTab.length;    // ForwardingNode——正在迁徙中的node,这个node的hash值是 MOVED    // 当其余线程发现此node时,会跳过。起到占位作用    ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);    // advance为true,则阐明须要进行下个地位的迁徙    boolean advance = true;    // 实现状态    boolean finishing = false; // to ensure sweep before committing nextTab    // i是地位索引下标    // bound是以后线程能够解决的区间的最小边界    for (int i = 0, bound = 0;;) {        Node<K,V> f; int fh;        // 管制i的递加(从后向前)        while (advance) {            int nextIndex, nextBound;            // 如果i-->=bound,或者实现状态为true,阐明迁徙工作曾经实现。会将advance批改为false            // 第一次进入循环,个别会进入上面分支代码(i--无奈通过)。            if (--i >= bound || finishing)                advance = false;            // 当线程进入会选取最新的转移下标            // 如果 transferIndex <=0,意味着没有区间了,扩容可完结。            else if ((nextIndex = transferIndex) <= 0) {                i = -1;                advance = false;            }            // CAS批改 transferIndex(length-区间值)。            else if (U.compareAndSetInt                     (this, TRANSFERINDEX, nextIndex,                      nextBound = (nextIndex > stride ?                                   nextIndex - stride : 0))) {                // 获取以后线程可进来区间的最小下标                bound = nextBound;                // i是以后线程能够解决的以后区间的最大下标                i = nextIndex - 1;                advance = false;            }        }        // 对i的状态进行判断?        if (i < 0 || i >= n || i + n >= nextn) {            int sc;            if (finishing) {                // 实现扩容的状况下,对相干属性进行更新                nextTable = null;                table = nextTab;                sizeCtl = (n << 1) - (n >>> 1);                return;            }            // CAS操作将sizeCtl-1            // sizeCtl 在迁徙前会设置为 (rs << RESIZE_STAMP_SHIFT) + 2。而后,每有一个线程参加迁徙就会将 sizeCtl 加 1            // 这里去 -1 ,代表线程实现了属于本人的工作            if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {                // 工作实现,可return                if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)                    return;                // 阐明 (sc - 2) == resizeStamp(n) << RESIZE_STAMP_SHIFT,即所有的迁徙工作已实现                finishing = advance = true;                i = n; // recheck before commit            }        }        // 原数组下标i处节点若为空,则放入ForwardingNode(占位)        else if ((f = tabAt(tab, i)) == null)            advance = casTabAt(tab, i, null, fwd);        // 阐明被其余线程占位了。持续下一个地位        else if ((fh = f.hash) == MOVED)            advance = true; // already processed        else {            // 到此处阐明,以后下标有理论值,并且未被占位解决。            // 对其加锁,筹备进行迁徙            synchronized (f) {                if (tabAt(tab, i) == f) {                    // 将链表一分为二,并找到原链表中的lastRun,而后lastRun和其之后的节点进行迁徙                    // lastRun之前的节点进行克隆后,分到两个链表中                    Node<K,V> ln, hn;                    // 头结点hash>0,是链表,否则是红黑树                    if (fh >= 0) {                        // 对原数组长度进行与运算                        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;                            }                        }                        // 设置低位节点                        if (runBit == 0) {                            ln = lastRun;                            hn = null;                        }                        // 设置高位节点                        else {                            hn = lastRun;                            ln = null;                        }                        // 循环生成两个链表                        for (Node<K,V> p = f; p != lastRun; p = p.next) {                            int ph = p.hash; K pk = p.key; V pv = p.val;                            if ((ph & n) == 0)                                ln = new Node<K,V>(ph, pk, pv, ln);                            else                                hn = new Node<K,V>(ph, pk, pv, hn);                        }                        // 低位链表放在新数组下标i处                        setTabAt(nextTab, i, ln);                        // 高位链表放在新数组下标i+n处                        setTabAt(nextTab, i + n, hn);                        // 原数组下标i处进行占位,示意处理完毕                        setTabAt(tab, i, fwd);                        advance = true;                    }                    else if (f instanceof 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;                    }                }            }        }    }}