Java 并发 Hashmap initTable() 为什么要使用 try/finally 块?

2024-01-30

我一直在查看以下代码(来自here https://hg.openjdk.java.net/jdk/jdk13/file/0368f3a073a9/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java)'

/**
 * Initializes table, using the size recorded in sizeCtl.
 */
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.compareAndSetInt(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;
}

有人可以解释为什么需要 try 块吗?


未经检查的异常和错误作为一个概念而存在。如果你打电话.put()在 ConcurrentHashMap 上,并且内存非常紧张,该映射可能会尝试创建一个数组,并且该调用可能会因 OutOfMemoryError 而失败。代码仍将继续(也许在捕获此内容的 catch 块处),并且对该映射的引用仍然存在。如果发生这种情况后,地图崩溃并完全失效,因为 sizeCtl 的值已损坏,那就有点糟糕了。

重点是finally 块,它恢复了sizeCtl价值。这用于多种用途,值得注意的是包括管理哪个线程可以访问。如果没有,任何其他看跌期权都将永远旋转。

其相关性(例如,这里发生可抛出的频率,与删除“尝试”和“最后”并以结尾sizeCtl = sc;没有 try/finally 的额外开销)很低,但如果相关的话,它是相当相关的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 并发 Hashmap initTable() 为什么要使用 try/finally 块? 的相关文章

随机推荐