了解ConcurrentHashMap计算方法的代码

Ada*_*ker 46 java multithreading concurrenthashmap

刚刚在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;
Run Code Online (Sandbox Code Playgroud)

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

这个动作有什么意义?这是一个错误还是会引起一些我不知道的不明显的副作用?

ps jdk1.8.0_131

And*_*ner 39

casTabAt(tab, i, null, r)
Run Code Online (Sandbox Code Playgroud)

正在发布引用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);
}
Run Code Online (Sandbox Code Playgroud)

因为c正在被放入tab,所以它可能被另一个线程访问,例如在putVal.因此,这个synchronized块是必要的,以排除其他线程与其他同步的事情Node.

  • "暴露"可能是一个更好的选择 (5认同)
  • @Caleth我已经在考虑将其更改为"发布",就像在"不安全的发布"中一样(尽管在这种情况下它并非"不安全";仅仅是在当前执行线程之外提供引用的一个众所周知的术语) . (2认同)

Kay*_*man 16

虽然此时r是一个新变量,但它会table立即放入内部if (casTabAt(tab, i, null, r)),此时另一个线程可以在代码的不同部分访问它.

内部非javadoc评论如此描述

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


Eug*_*ene 5

这里只需 0.02 美元

您所显示的实际上只是ReservationNode- 意味着垃圾箱是空的并且已预订了某个节点。请注意,此方法稍后会用真实的节点替换此节点:

 setTabAt(tab, i, node);
Run Code Online (Sandbox Code Playgroud)

据我所知,这样做是为了使替换是原子的。一旦通过发布casTabAt并且如果其他线程看到它 - 它们就无法同步它,因为锁已经被持有。

另请注意,当 bin 中有一个 Entry 时,第一个 Node 用于同步(它在方法中更靠下的位置):

boolean added = false;
            synchronized (f) { // locks the bin on the first Node
                if (tabAt(tab, i) == f) {
......
Run Code Online (Sandbox Code Playgroud)

作为侧节点,此方法在 中发生了更改9,自 以来8。例如运行这段代码:

 map.computeIfAbsent("KEY", s -> {
    map.computeIfAbsent("KEY"), s -> {
        return 2;
    }
 })
Run Code Online (Sandbox Code Playgroud)

永远不会获得第 8 名,但会获得第Recursive Update9 名。