zoukankan      html  css  js  c++  java
  • ConcurrentHashMap中sizeCtl的说明

      ConcurrentHashMap设计很强,其中sizeCtl设计十分巧妙。但是在网上查资料真的是以讹传讹啊。所以,我来写一下sizeCtl的说明。

      sizeCtl有多重含义,其中除了扩容的时候难理解外,其他的比较好理解

    ·    1  如果一个ConcurrentHashMap正在初始化,值为-1

       2  ConcurrentHashMap初始化完成正在使用,置为size * 0.75

      3 扩容的时候,是一个负值

      我们今天就来看看这个扩容的时候的值是怎么来的

    private final void tryPresize(int size) {
            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.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;
                        }
                    }
                }
                else if (c <= sc || n >= MAXIMUM_CAPACITY)
                    break;
                else if (tab == table) {
                    int rs = resizeStamp(n);
                    if (sc < 0) {
                        Node<K,V>[] nt;
                        if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                            sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                            transferIndex <= 0)
                            break;
                        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);
                }
            }
        }

      如果第一个线程触发了扩容,那么注意这句话

    U.compareAndSwapInt(this, SIZECTL, sc,
                                                 (rs << RESIZE_STAMP_SHIFT) + 2)
    rs 的值是怎么来的呢
    int rs = resizeStamp(n);
    从方法名上看,这个值叫扩容标识戳。
    我们就以n=16为例,
    static final int resizeStamp(int n) {
            return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
        }
    Integer.numberOfLeadingZeros(n)就不分析具体实现了,该方法的含义是一个数的最高位第一个非0开始算起,到他的最高位有多少个0。
    比如n=16,那么 Integer.numberOfLeadingZeros(n)返回值就是27.
    因为16是 10000。一个int是32位,32-5就是27.
    (1 << (RESIZE_STAMP_BITS - 1)),其中 RESIZE_STAMP_BITS = 16。 也就是说该表达式的值是一个1,后面跟15个0.这里请注意,这个1的事情。
    然后呢,两个值做或运算,那么刚才的1就会让这个返回的int值的低16位中的第 16位是1.

    我们再看
    U.compareAndSwapInt(this, SIZECTL, sc,
                                                 (rs << RESIZE_STAMP_SHIFT) + 2)
    (rs << RESIZE_STAMP_SHIFT) + 2)

    rs左移16位,还记得刚才说的1嘛,最高位是符号位,所以这个事肯定是一个负数。同时左移16位后,低16位就全部是0。然后加2.那么不看高16位,低16位的值就是2。
    这也就是sizeCtl低16位表示的是参与扩容的线程数 + 1。

    当最后一个扩容线程准备收尾的判断依据也是
    sizeCtl-1 后是不是等于1。

    以上就是sizeCtl的意义,总结下就是高16位是扩容标识戳,低16位是扩容线程数+1。

     

      

  • 相关阅读:
    微信公众号 发送客服消息
    juqery 点击谁获取他的值,赋给input标签
    微信执行退出页面,直接回到微信对话窗口
    微信jssdk上传图片,一张一张的上传 和 一次性传好几张
    juqery 判断所有input 不能为空 判断只能为数字 判断身份证号:18位和15位 判断是否银行卡号
    php foreach
    现在越来越喜欢用ajax传值了,这样能让网站的体验性很好,今天就总结了一下常用的
    有时候不用explode截取字符串了,可以用用substr()
    ztree 文件夹类型的 树状图
    POJ 1065 Wooden Sticks
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13838947.html
Copyright © 2011-2022 走看看