了解 ConcurrentHashMap 计算方法的代码

2022-08-31 22:34:15

刚刚在 ConcurrentHashMap 计算方法中发现了这个奇怪的代码:(第 1847 行)

public V compute(K key,
                 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    ...
    Node<K,V> r = new ReservationNode<K,V>();
    synchronized (r) {   <--- what is this?
        if (casTabAt(tab, i, null, r)) {
            binCount = 1;
            Node<K,V> node = null;

因此,代码对仅对当前线程可用的新变量执行同步。这意味着没有其他线程可以竞争此锁定或导致内存限制效应。

这个动作的意义何在?这是一个错误还是它会导致一些我不知道的不明显的副作用?

附言 jdk1.8.0_131


答案 1
casTabAt(tab, i, null, r)

正在发布对 的引用。r

static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                    Node<K,V> c, Node<K,V> v) {
    return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}

因为 被放入 ,所以有可能它被另一个线程访问,例如在 putVal 中。因此,此块对于排除其他线程执行其他同步操作是必要的。ctabsynchronizedNode


答案 2

虽然此时是一个新变量,但它会立即放入内部,此时另一个线程能够在代码的不同部分中访问它。rtableif (casTabAt(tab, i, null, r))

内部非javadoc注释这样描述它

在空条柱中插入(通过 put 或其变体)第一个节点只需将其 CASing 到条柱即可执行。这是迄今为止在大多数键/哈希分布下放置操作的最常见情况。其他更新操作(插入、删除和替换)需要锁定。我们不想浪费将不同的锁对象与每个条柱相关联所需的空间,因此而是使用箱列表本身的第一个节点作为锁。对这些锁的锁定支持依赖于内置的“同步”监视器。