ConcurrentHashMap 源码分析

ConcurrentHashMap

ConcurrentHashMap 能解决什么问题?什么时候使用 ConcurrentHashMap?

1)ConcurrentHashMap 支持高并发的读写,是线程安全的哈希表。
2)ConcurrentHashMap 的键和值都不能为 null。
3)ConcurrentHashMap 是弱一致性的,写操作变更的数据不一定能立即被其他线程读取。

如何使用 ConcurrentHashMap?

1)需要并发读写对象映射关系的场景下。
2)ConcurrentHashMap 常用于本地缓存。

使用 ConcurrentHashMap 有什么风险?

1)ConcurrentHashMap 是弱一致性的。

ConcurrentHashMap 核心操作的实现原理?

创建实例

    /**
     *  ConcurrentHashMap 的最大容量
     */
    private static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * ConcurrentHashMap 的初始化容量
     */
    private static final int DEFAULT_CAPACITY = 16;

    /**
     * The largest possible (non-power of two) array size.
     * Needed by toArray and related methods.
     */
    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * ConcurrentHashMap 的默认并发度
     */
    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

    /**
     * ConcurrentHashMap 的加载因子,覆盖该值只会影响其初始容量。
     */
    private static final float LOAD_FACTOR = 0.75f;

    /**
     *  链表红黑树化的长度阈值
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     *  红黑树链表化的长度阈值
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     *  bucket 链表红黑树化的最小 bucket 数,
     *  即 ConcurrentHashMap 的容量必须达到 64 才会执行红黑树化操作
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

    /**
     *  扩容过程中,单个线程最少负责从旧 table 中转移的 bucket 数目,
     *  以支持多线程扩容。
     */
    private static final int MIN_TRANSFER_STRIDE = 16;

    /**
     *  用于生成 sizeCtl 标记的位的数目
     * Must be at least 6 for 32bit arrays.
     */
    private static final int RESIZE_STAMP_BITS = 16;

    /**
     *  能够帮助扩容的最大线程数量
     * Must fit in 32 - RESIZE_STAMP_BITS bits.
     */
    private static final int MAX_RESIZERS = (1 << 32 - ConcurrentHashMap.RESIZE_STAMP_BITS) - 1;

    /**
     * The bit shift for recording size stamp in sizeCtl.
     */
    private static final int RESIZE_STAMP_SHIFT = 32 - ConcurrentHashMap.RESIZE_STAMP_BITS;

    /*
     * Encodings for Node hash fields. See above for explanation.
     */
    static final int MOVED     = -1; // ForwardingNode 节点的哈希值
    static final int TREEBIN   = -2; // TreeBin 节点的哈希值
    static final int RESERVED  = -3; // ReservationNode 节点的哈希值
    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash

    /** 当前 JVM 可用的 CPU 数目 */
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    /**
     *  在第一次插入时执行初始化
     */
    transient volatile Node<K,V>[] table;

    /**
     *  扩容过程中的新 table,只有在扩容时才有值,其他时间为 null
     */
    private transient volatile Node<K,V>[] nextTable;

    /**
     *  没有发生竞争或表初始化期间,累元素总数的基础值
     */
    private transient volatile long baseCount;

    /**
     * -1:哈希表正在执行初始化
     * -N:哈希表正在扩容
     * 20:ConcurrentHashMap 实例新建
     * +N:下一次扩容的阈值
     */
    private transient volatile int sizeCtl;

    /**
     *  扩容过程中,下一个允许分割的索引
     */
    private transient volatile int transferIndex;

    /**
     *  resizing and/or creating CounterCells 的标记值
     */
    private transient volatile int cellsBusy;

    /**
     *  并发累加元素总数的单元
     */
    private transient volatile CounterCell[] counterCells;

    /**
     *  创建一个初始容量为 16 的空 ConcurrentHashMap 实例
     */
    public ConcurrentHashMap() {
    }

    /**
     *  创建一个初始容量为【最接近 initialCapacity 的 2 的幂】的空 ConcurrentHashMap 实例
     */
    public ConcurrentHashMap(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException();
        }
        final int cap = initialCapacity >= ConcurrentHashMap.MAXIMUM_CAPACITY >>> 1 ?
                ConcurrentHashMap.MAXIMUM_CAPACITY :
                    ConcurrentHashMap.tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1);
        this.sizeCtl = cap;
    }

添加元素

    /**
     *  往 ConcurrentHashMap 实例中添加新的键值对,键和值都不能为 null
     */
    @Override
    public V put(K key, V value) {
        return putVal(key, value, false);
    }

    /** Implementation for put and putIfAbsent */
    /**
     * @param key 键
     * @param value 值
     * @param onlyIfAbsent 只有键不存在时才添加
     */
    final V putVal(K key, V value, boolean onlyIfAbsent) {
        // 非空判断
        if (key == null || value == null) {
            throw new NullPointerException();
        }
        // 计算哈希值
        final int hash = ConcurrentHashMap.spread(key.hashCode());
        int binCount = 0;
        // 读取 table
        for (Node<K,V>[] tab = table;;) {
            /**
             * f:first 表示 bucket 的首元素
             * n:length 表示 table 长度
             * i:index 表示目标索引
             * fh:first hash 表示首元素的哈希值
             * fk:first key 表示首元素的键
             * fv:first value 表示首元素的值
             */
            Node<K,V> f; int n, i, fh; K fk; V fv;
            // 1)table 为空,则表示 ConcurrentHashMap 还未初始化
            if (tab == null || (n = tab.length) == 0) {
                // 执行初始化操作
                tab = initTable();
            // 2)通过哈希值定位到的 bucket 为 null    
            } else if ((f = ConcurrentHashMap.tabAt(tab, i = n - 1 & hash)) == null) {
                // 则基于给定键和值创建新的节点,并尝试通过原子操作写入 bucket
                if (ConcurrentHashMap.casTabAt(tab, i, null, new Node<>(hash, key, value)))
                {
                    // 写入成功,则直接返回
                    break;                   // no lock when adding to empty bin
                }
            }
            // 3)首节点的哈希值为 MOVED 表示当前哈希表在扩容
            else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
                // 尝试帮助进行元素迁移
                tab = helpTransfer(tab, f);
            // 4)如果是 onlyIfAbsent 模式,并且键已经存在,其值不为 null,则直接返回旧值
            } 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;
            // 5)将节点加入到链表或红黑树中  
            } else {
                V oldVal = null;
                // 获取 bucket 首节点的对象监视器实现线程同步
                synchronized (f) {
                    // 如果首节点已经变更,则出现了并发写,需要重新进行处理
                    if (ConcurrentHashMap.tabAt(tab, i) == f) {
                        // 1)当前 bucket 是否是链表
                        if (fh >= 0) {
                            binCount = 1;
                            // 遍历链表中的每个节点
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
                                // 如果找到匹配的节点
                                if (e.hash == hash &&
                                        ((ek = e.key) == key ||
                                        ek != null && key.equals(ek))) {
                                    // 读取旧值
                                    oldVal = e.val;
                                    // 尝试写入新值
                                    if (!onlyIfAbsent) {
                                        e.val = value;
                                    }
                                    // 退出循环
                                    break;
                                }
                                final Node<K,V> pred = e;
                                /**
                                 *  读取当前节点的后置节点,如果其为 null 则说明到达了链表尾部
                                 */
                                if ((e = e.next) == null) {
                                    // 直接在尾部新增节点
                                    pred.next = new Node<>(hash, key, value);
                                    // 退出循环
                                    break;
                                }
                            }
                        }
                        // 2)当前 bucket 是否是红黑树
                        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");
                        }
                    }
                }
                if (binCount != 0) {
                    // 单向链表的长度已经达到红黑树化阈值 8+1
                    if (binCount >= ConcurrentHashMap.TREEIFY_THRESHOLD) {
                        // 执行链表的红黑树化过程
                        treeifyBin(tab, i);
                    }
                    if (oldVal != null) {
                        return oldVal;
                    }
                    break;
                }
            }
        }
        // 增加元素计数值
        addCount(1L, binCount);
        return null;
    }

    /**
     *  使用记录在 sizeCtl 中的值初始化哈希表.
     */
    private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        while ((tab = table) == null || tab.length == 0) {
            // 1)已经有其他线程在执行初始化操作
            if ((sc = sizeCtl) < 0) {
                // 当前线程让出 CPU 等待其他线程初始化完毕
                Thread.yield(); // lost initialization race; just spin
            // 2)原子更新 SIZECTL 的值为 -1
            } else if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, -1)) {
                try {
                    if ((tab = table) == null || tab.length == 0) {
                        final int n = sc > 0 ? sc : ConcurrentHashMap.DEFAULT_CAPACITY;
                        // 新建 table
                        final
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        // 写入 table
                        table = tab = nt;
                        // 计算 sizeCtl
                        sc = n - (n >>> 2);
                    }
                } finally {
                    // 写入 sizeCtl
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }

    /**
     *  如果哈希表正在执行扩容,则尝试帮助转移旧 table 中的元素到新 table 中
     */
    final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
        Node<K,V>[] nextTab; int sc;
        /**
         * 1)首节点是 ForwardingNode &&
         * 2)首节点的 nextTable 存在
         */
        if (tab != null && f instanceof ForwardingNode &&
                (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
            // 读取用于扩容长度为 tab.length 的哈希表的标记
            final int rs = ConcurrentHashMap.resizeStamp(tab.length);
            while (nextTab == nextTable && table == tab &&
                    (sc = sizeCtl) < 0) {
                // 如果帮助扩容的线程已经满了或已经迁移完毕
                if (sc >>> ConcurrentHashMap.RESIZE_STAMP_SHIFT != rs || sc == rs + 1 ||
                        sc == rs + ConcurrentHashMap.MAX_RESIZERS || transferIndex <= 0) {
                    // 直接退出
                    break;
                }
                // 尝试加入扩容大军
                if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, sc + 1)) {
                    // 加入成功则执行旧 table 的迁移
                    transfer(tab, nextTab);
                    break;
                }
            }
            return nextTab;
        }
        return 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;
        if (tab != null) {
            // 1)哈希表的容量小于 64
            if ((n = tab.length) < ConcurrentHashMap.MIN_TREEIFY_CAPACITY) {
                // 执行双倍扩容
                tryPresize(n << 1);
            // 2)读取 bucket 首节点后进行红黑树化
            } else if ((b = ConcurrentHashMap.tabAt(tab, index)) != null && b.hash >= 0) {
                synchronized (b) {
                    // 如果没有其他线程并发修改此 bucket
                    if (ConcurrentHashMap.tabAt(tab, index) == b) {
                        /**
                         * hd:head
                         * tl:tail
                         */
                        TreeNode<K,V> hd = null, tl = null;
                        // 遍历单向链表,将所有的节点装换为树节点
                        for (Node<K,V> e = b; e != null; e = e.next) {
                            final TreeNode<K,V> p =
                                    new TreeNode<>(e.hash, e.key, e.val,
                                            null, null);
                            if ((p.prev = tl) == null) {
                                hd = p;
                            } else {
                                tl.next = p;
                            }
                            tl = p;
                        }
                        // 执行红黑树化过程
                        ConcurrentHashMap.setTabAt(tab, index, new TreeBin<>(hd));
                    }
                }
            }
        }
    }

    /**
     *  尝试进行扩容
     */
    private final void tryPresize(int size) {
        final int c = size >= ConcurrentHashMap.MAXIMUM_CAPACITY >>> 1 ? ConcurrentHashMap.MAXIMUM_CAPACITY :
            ConcurrentHashMap.tableSizeFor(size + (size >>> 1) + 1);
        int sc;
        // 当前还未执行扩容操作
        while ((sc = sizeCtl) >= 0) {
            final Node<K,V>[] tab = table; int n;
            // 1)table 为空,则执行初始化操作
            if (tab == null || (n = tab.length) == 0) {
                n = sc > c ? sc : c;
                if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, -1)) {
                    try {
                        if (table == tab) {
                            @SuppressWarnings("unchecked")
                            final
                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                            table = nt;
                            sc = n - (n >>> 2);
                        }
                    } finally {
                        sizeCtl = sc;
                    }
                }
            }
            // 2)目标 size 小于扩容阈值或 table 容量超出最大容量
            else if (c <= sc || n >= ConcurrentHashMap.MAXIMUM_CAPACITY) {
                break;
            // 3)没有其他线程执行扩容操作   
            } else if (tab == table) {
                final int rs = ConcurrentHashMap.resizeStamp(n);
                // 尝试原子更新控制标识
                if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc,
                        (rs << ConcurrentHashMap.RESIZE_STAMP_SHIFT) + 2)) {
                    // 更新成功则执行旧 table 的数据迁移
                    transfer(tab, null);
                }
            }
        }
    }

    /**
     *  将旧 table 中的 bucket 迁移到新 table 中
     */
    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
        // 旧table的长度
        final int n = tab.length;
        // 当前线程连续迁移的 bucket 数,一般都是 16
        int stride;
        if ((stride = ConcurrentHashMap.NCPU > 1 ? (n >>> 3) / ConcurrentHashMap.NCPU : n) < ConcurrentHashMap.MIN_TRANSFER_STRIDE)
        {
            stride = ConcurrentHashMap.MIN_TRANSFER_STRIDE; // subdivide range
        }
        // 如果当前线程是第一个执行扩容的线程,则执行新 table 的初始化
        if (nextTab == null) {            // initiating
            try {
                @SuppressWarnings("unchecked")
                final
                // 双倍扩容
                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
                nextTab = nt;
            } catch (final Throwable ex) {      // try to cope with OOME
                sizeCtl = Integer.MAX_VALUE;
                return;
            }
            // 写入新 table
            nextTable = nextTab;
            // 写入下一个迁移的起始索引
            transferIndex = n;
        }
        final int nextn = nextTab.length;
        // 创建 ForwardingNode
        final ForwardingNode<K,V> fwd = new ForwardingNode<>(nextTab);
        // 是否能处理下一个 bucket
        boolean advance = true;
        // 是否完成扩容
        boolean finishing = false; // to ensure sweep before committing nextTab
        // 死循环扩容
        for (int i = 0, bound = 0;;) {
            /**
             *  f:first 表示首节点
             *  fh:first hash 表示首节点的哈希值
             */
            Node<K,V> f; int fh;
            // 如果能处理下一个 bucket
            while (advance) {
                int nextIndex, nextBound;
                /**
                 *  1)递减bucket下标,如果已经达到当次处理的最小下标,则需要重新申领
                 *  2)扩容已完成,则尝试进行二次校验
                 */
                if (--i >= bound || finishing) {
                    // 当前 bucket 未迁移
                    advance = false;
                    // 2)读取迁移索引,如果迁移索引为 0,表示所有的 bucket 已经申领完毕
                } else if ((nextIndex = transferIndex) <= 0) {
                    i = -1;
                    advance = false;
                }
                // 3)尝试申领新的一段 buckets
                else if (ConcurrentHashMap.U.compareAndSetInt
                        (this, ConcurrentHashMap.TRANSFERINDEX, nextIndex,
                                nextBound = nextIndex > stride ?
                                        nextIndex - stride : 0)) {
                    // 更新本次能迁移的最小 bucket 索引
                    bound = nextBound;
                    // 读取本次迁移的起始 bucket 索引
                    i = nextIndex - 1;
                    advance = false;
                }
            }
            /**
             *  申领的 bucket 已经全部迁移完毕
             */
            if (i < 0 || i >= n || i + n >= nextn) {
                int sc;
                // 1)如果已经扩容完成
                if (finishing) {
                    nextTable = null;
                    // 写入新 table
                    table = nextTab;
                    // 写入新 sizeCtl
                    sizeCtl = (n << 1) - (n >>> 1);
                    return;
                }
                // 当前线程完成了其申领 buckets 的迁移工作
                if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc = sizeCtl, sc - 1)) {
                    /**
                     *  如果不是最后一个完成迁移的线程
                     *  1)第一个执行扩容的线程会将 sizeCtl 设置为 ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT + 2
                     *  2)每个帮助扩容的线程申领到 buckets 会将其 +1,完成申领 buckets 迁移工作后会将其 -1
                     *  3)如果当前线程是最后一个完成迁移工作的线程,则其值为 ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT + 2
                     */
                    if (sc - 2 != ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT) {
                        // 则直接返回
                        return;
                    }
                    // 最后一个扩容线程将会设置完成标志,并执行二次校验
                    finishing = advance = true;
                    i = n; // recheck before commit
                }
            }
            /**
             *  2)如果旧 table 的指定 bucket 为 null,表示无需执行数据迁移,
             *  则直接将其设置为 ForwardingNode
             */
            else if ((f = ConcurrentHashMap.tabAt(tab, i)) == null) {
                advance = ConcurrentHashMap.casTabAt(tab, i, null, fwd);
                /**
                 *  3)执行迁移完成的二次校验,当前 bucket 已经处理过了
                 */
            } else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
                advance = true; // already processed
                // 4)迁移指定 bucket
            } else {
                synchronized (f) {
                    // 处理过程中未发生并发修改
                    if (ConcurrentHashMap.tabAt(tab, i) == f) {
                        /**
                         *  ln:low node 表示低位节点
                         *  hn:high node 表示高位节点
                         */
                        Node<K,V> ln, hn;
                        // 1)当前 bucket 是单向链表
                        if (fh >= 0) {
                            // 将节点哈希值和table长度进行与操作
                            int runBit = fh & n;
                            // 读取最后处理的节点
                            Node<K,V> lastRun = f;
                            for (Node<K,V> p = f.next; p != null; p = p.next) {
                                final int b = p.hash & n;
                                if (b != runBit) {
                                    runBit = b;
                                    lastRun = p;
                                }
                            }
                            // 最后一个处理的节点哈希值 < 2^n
                            if (runBit == 0) {
                                // 写入低位节点
                                ln = lastRun;
                                hn = null;
                            }
                            else {
                                // 写入高位节点
                                hn = lastRun;
                                ln = null;
                            }
                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
                                final int ph = p.hash; final K pk = p.key; final V pv = p.val;
                                // 当前节点是低位节点
                                if ((ph & n) == 0) {
                                    ln = new Node<>(ph, pk, pv, ln);
                                // 当前节点是高位节点    
                                } else {
                                    hn = new Node<>(ph, pk, pv, hn);
                                }
                            }
                            // 将处理后的 bucket 写入新table的低位
                            ConcurrentHashMap.setTabAt(nextTab, i, ln);
                            // 将处理后的 bucket 写入新table的高位
                            ConcurrentHashMap.setTabAt(nextTab, i + n, hn);
                            // 更新旧table的 bucket为ForwardingNode,表示当前bucket已经完成迁移
                            ConcurrentHashMap.setTabAt(tab, i, fwd);
                            // 继续处理下一个 bucket
                            advance = true;
                        }
                        // 2)当前 bucket 是红黑树
                        else if (f instanceof TreeBin) {
                            final TreeBin<K,V> t = (TreeBin<K,V>)f;
                            /**
                             * lo:low
                             * hi:high
                             * loTail:lowTail
                             * hiTail:highTail
                             * lc:low count
                             * hc:high count
                             */
                            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) {
                                final int h = e.hash;
                                final TreeNode<K,V> p = new TreeNode<>
                                (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 <= ConcurrentHashMap.UNTREEIFY_THRESHOLD ? ConcurrentHashMap.untreeify(lo) :
                                hc != 0 ? new TreeBin<>(lo) : t;
                                hn = hc <= ConcurrentHashMap.UNTREEIFY_THRESHOLD ? ConcurrentHashMap.untreeify(hi) :
                                    lc != 0 ? new TreeBin<>(hi) : t;
                                    // 写入新 table 的 bucket 中
                                    ConcurrentHashMap.setTabAt(nextTab, i, ln);
                                    ConcurrentHashMap.setTabAt(nextTab, i + n, hn);
                                    ConcurrentHashMap.setTabAt(tab, i, fwd);
                                    // 继续处理下一个 bucket
                                    advance = true;
                        }
                    }
                }
            }
        }
    }

读取元素

    /**
     *  根据键读取值,如果键不存在,则返回 null
     */
    @Override
    public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
        final int h = ConcurrentHashMap.spread(key.hashCode());
        // table 不为空,并且通过键的哈希值映射的 bucket 首节点不为 null
        if ((tab = table) != null && (n = tab.length) > 0 &&
                (e = ConcurrentHashMap.tabAt(tab, n - 1 & h)) != null) {
            // 1)首节点哈希值和目标键的哈希值一致
            if ((eh = e.hash) == h) {
                // 同时键也相等
                if ((ek = e.key) == key || ek != null && key.equals(ek)) {
                    // 直接返回值
                    return e.val;
                }
            }
            // 2)当前 bucket 是红黑树或正在执行扩容,则使用 find 方法查找键
            else if (eh < 0) {
                // 找到则返回其值,否则返回 null
                return (p = e.find(h, key)) != null ? p.val : null;
            }
            // 当前 bucket 是一个单向链表,则执行链表查找
            while ((e = e.next) != null) {
                if (e.hash == h &&
                        ((ek = e.key) == key || ek != null && key.equals(ek))) {
                    return e.val;
                }
            }
        }
        // 未找到键,则返回 null
        return null;
    }

    /**
     *  如果目标键存在,则返回其关联的值,否则返回默认值
     */
    @Override
    public V getOrDefault(Object key, V defaultValue) {
        V v;
        return (v = get(key)) == null ? defaultValue : v;
    }

替换值

    /**
     *  如果存在目标键,则替换其值,并返回旧值;否则返回 null
     */
    @Override
    public V replace(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException();
        }
        return replaceNode(key, value, null);
    }

    final V replaceNode(Object key, V value, Object cv) {
        // 计算 key 的哈希值
        final int hash = ConcurrentHashMap.spread(key.hashCode());
        // 读取 table 后进入死循环
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            // 1)table 为空,或通过哈希值定位的 bucket 为空,则直接返回 null
            if (tab == null || (n = tab.length) == 0 ||
                    (f = ConcurrentHashMap.tabAt(tab, i = n - 1 & hash)) == null) {
                break;
            // 2)table 正在扩容,则尝试帮助其扩容    
            } else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
                tab = helpTransfer(tab, f);
            // 执行键查找    
            } else {
                V oldVal = null;
                boolean validated = false;
                // 锁住头结点
                synchronized (f) {
                    // 头结点未发生变更
                    if (ConcurrentHashMap.tabAt(tab, i) == f) {
                        // 1)当前 bucket 是链表
                        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))) {
                                    // 找到了匹配的键
                                    final V ev = e.val;
                                    /**
                                     *  1)cv==null 表示无条件替换
                                     *  2)cv == ev || ev != null && cv.equals(ev) 表示 cas 替换
                                     */
                                    if (cv == null || cv == ev ||
                                            ev != null && cv.equals(ev)) {
                                        // 读取旧值
                                        oldVal = ev;
                                        // 1)目标值不为 null,则表示节点替换
                                        if (value != null) {
                                            e.val = value;
                                        /**
                                         * 2)目标值为 null 则表示节点删除
                                         * pred != null 表示当前节点在首节点之后
                                         */
                                        } else if (pred != null) {
                                            pred.next = e.next;
                                        // pred == null 表示当前节点是首节点,则直接 cas 更新为第二个节点 
                                        } else {
                                            ConcurrentHashMap.setTabAt(tab, i, e.next);
                                        }
                                    }
                                    break;
                                }
                                // 继续查找下一个节点
                                pred = e;
                                // 如果已经达到尾部,则表示未找到匹配的键
                                if ((e = e.next) == null) {
                                    break;
                                }
                            }
                        }
                        // 2)当前 bucket 是红黑树
                        else if (f instanceof TreeBin) {
                            validated = true;
                            final 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) {
                                final V pv = p.val;
                                /**
                                 *  1)cv==null 表示无条件替换
                                 *  2)cv == ev || ev != null && cv.equals(ev) 表示 cas 替换
                                 */
                                if (cv == null || cv == pv ||
                                        pv != null && cv.equals(pv)) {
                                    oldVal = pv;
                                    // 1)目标值不为 null,则表示节点替换
                                    if (value != null) {
                                        p.val = value;
                                    // 2)目标值为 null,则表示节点删除
                                    } else if (t.removeTreeNode(p)) {
                                        ConcurrentHashMap.setTabAt(tab, i, ConcurrentHashMap.untreeify(t.first));
                                    }
                                }
                            }
                        }
                        else if (f instanceof ReservationNode) {
                            throw new IllegalStateException("Recursive update");
                        }
                    }
                }
                // 已经完成查找
                if (validated) {
                    if (oldVal != null) {
                        if (value == null) {
                            // 旧值不为 null,新值为 null 表示删除了一个存在的节点,递减总数
                            addCount(-1L, -1);
                        }
                        return oldVal;
                    }
                    break;
                }
            }
        }
        return null;
    }

    /**
     *  如果键 key 存在 && 旧值和 oldValue 相等,则将其替换为 newValue
     */
    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        if (key == null || oldValue == null || newValue == null) {
            throw new NullPointerException();
        }
        return replaceNode(key, newValue, oldValue) != null;
    }

节点删除

    /**
     *  指定的 key 存在,则删除节点并返回旧值;否则返回 null
     */
    @Override
    public V remove(Object key) {
        return replaceNode(key, null, null);
    }

    /**
     *  如果 key 存在 && 旧值和 value 相等,则将其删除,删除成功返回 true,否则返回 false
     */
    @Override
    public boolean remove(Object key, Object value) {
        if (key == null) {
            throw new NullPointerException();
        }
        return value != null && replaceNode(key, null, value) != null;
    }

posted on 2018-12-04 20:24  竺旭东  阅读(110)  评论(0编辑  收藏  举报

导航