ConcurrentHashMap1.8扩容实现详解

上一篇ConcurrentHashMap源码解析中只是初步分析了ConcurrentHashMap的实现,这篇将详细讲述ConcurrentHashMap的扩容实现过程。

触发扩容的情况

当往ConcurrentHashMap中插入一个Key/Value结点时,有可能触发扩容。

1.第一种情况; 如果新增结点后,所在链表的元素大于等于阈值8,则会调用treeifyBin()方法,把链表转化为红黑树,但是再进行结构转换之前,还需要对数组长度进行判断。
treeifyBin()方法:

private final void treeifyBin(Node<K,V>[] tab, int index) {
   
        Node<K,V> b; int n, sc;
        if (tab != null) {
   
            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));
                    }
                }
            }
        }
    }

treeifyBin()方法中有判断:

 if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
                tryPresize(n << 1);

如果数组长度n小于阈值MIN_TREEIFY_CAPACITY,则会调用tryPresize方法把数组长度扩大到原来的两倍。最终触发transfer()方法。

  1. 第二种情况;新增结点之后,putVal()方法中会调用addCount方法记录元素个数。并检查是否进行扩容,当元素个数达到阈值时,触发transfer()方法。

上述两种情况都最终提到了transfer()方法(transfer方法会重新调整结点位置),transfer()方法是真正意义上的扩容操作。

transfer()方法的实现
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
   
        int n = tab.length, stride;
        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)  //每个线程处理桶的最小数目,可以看出核数越高步长越小,最小16个。
            stride = MIN_TRANSFER_STRIDE; // subdivide range
        if (nextTab == null) {
   
            try {
   
                @SuppressWarnings("unchecked")
                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];  //扩容到2倍
                nextTab = nt;
            } catch (Throwable ex) {
         // try to cope with OOME
                sizeCtl = Integer.MAX_VALUE;  //扩容保护
                return;
            }
            nextTable = nextTab;
            transferIndex = n;  //扩容总进度,>=transferIndex的桶都已分配出去。
        }
        int nextn = nextTab.length;
          //扩容时的特殊节点,标明此节点正在进行迁移,扩容期间的元素查找要调用其find()方法在nextTable中查找元素。
        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab); 
        //当前线程是否需要继续寻找下一个可处理的节点
        boolean advance = true;
        boolean finishing = false; //所有桶是否都已迁移完成。
        for (int i = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值