• ConsurrentHashMap InitTable 疑问与思考


    ConsurrentHashMap InitTable 疑问与思考

    ConsurrentHashMap 作为单机下经常使用的一个线程安全Map值得我们学习一下,以下其初始化的过程的代码,以及学习过程中遇到的疑惑与自己的思考

     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
                else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                    try {
                        if ((tab = table) == null || tab.length == 0) {
                            int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                            @SuppressWarnings("unchecked")
                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                            table = tab = nt;
                            sc = n - (n >>> 2);
                        }
                    } finally {
                        sizeCtl = sc;
                    }
                    break;
                }
            }
            return tab;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1、多线程下该方法不加锁时如何保证线程安全的

    通常意义下的加锁,都是去检查一个东西是否被“其他”持有,如果被持有则本次加锁尝试失败。这里也是同样的思路,通过判断sc是否小于零来判断当前是否有其他线程操作,如果有其他线程操作到下面sc会被修改成**-1**来表示被加锁,同时CAS的操作保证了只能由一个线程修改成功,即只有一个线程能获得锁

    2、为什么使用while 而不是if

    initTable 的方法是为了完成初始化返回一个node数组,所以没有**“获取锁”线程需要陷入等待,等待其他线程完成初始化,所以该方法使用了while来让没有“获取锁”**的线程不断循环等待。

    3、为什么使用Thread.yield(),而不是return、sleep

    第二个问题说到需要循环等待所有自然不可能提前return,那为什么不用sleep,因为我们并不知道另一个线程什么时候完成初始化,也就不知道sleep多少秒,多了、少了都不合适,所以干脆就让出cpu时间片,等下一次再看看,如果其他线程完成了初始化就返回,否则重复以上。这其实就是源码中注释表达的含义:lost initialization race; just spin,退出竞争,不断自旋。

  • 相关阅读:
    alibaba国际版阿里巴巴API接入说明(阿里巴巴商品详情+关键词搜索商品列表)
    Python的PyQt框架的使用-创建主窗体篇
    算法系列二:插值查找、斐波那契查找
    android studio 找不到设备
    具体调用vue预览的功能
    消息队列,推拉模式的区别在哪?
    postgresql 安装教程
    Layui + Flask | 实现数据表格修改(案例篇)(09)
    优化sql语句的一般步骤
    Linux隐藏文件或文件夹
  • 原文地址:https://blog.csdn.net/weixin_43779268/article/details/126025274