【问题标题】:ConcurrentHashMap.initTable(), why check table is null twice?ConcurrentHashMap.initTable(),为什么检查表两次为空?
【发布时间】:2021-11-18 14:05:21
【问题描述】:

我正在学习java源代码,当我阅读ConcurrentHashMap源代码时,我对initTable()方法感到困惑,为什么要检查(tab = table) == null || tab.length == 0两次,首先是while(),然后是@987654323 @。我无法想象在什么情况下需要第二次检查。

我想可能是因为 JVM 重新排序了代码,把 sizeCtl = sc; 放在了 Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n]; 前面。这只是我的猜测,我不知道是否正确。

谁能解释一下,非常感谢。

 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;
    }

【问题讨论】:

    标签: java concurrenthashmap


    【解决方案1】:

    多个线程可能会竞争执行此操作(请参阅“初始化竞赛”注释)。

    解释一下代码:

    while(uninitialized) {
        acquire_lock(); //compareAndSwapInt...
        if(uninitialized) {
            do_init();
        }
    }
    

    外部检查是一种廉价的“解锁”测试。内部是万一其他人已经在whilecompareAndSwapInt 之间取得成功。

    【讨论】:

    • 不应该只有一个线程可以成功执行U.compareAndSwapInt(this, SIZECTL, sc, -1)吗?
    • @zysaaa sc = sizeCtl 正在捕获之前的值,如果它是-1,它就会屈服。大多数时候它会得到 0,因为它在 while 条件下是 0。但是如果sizeCtl 在while 和sc = sizeCtl 之间变化呢? sc&gt;0 会让你通过 compareAndSwapInt 才发现工作已经完成...
    • 现在很清楚了,非常感谢。
    • 那就考虑接受这个答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 2020-02-18
    • 2012-03-02
    相关资源
    最近更新 更多