Java ConcurrentHashMap的computeIfAbsent()方法是否支持基于密钥的“锁定”?

时间:2019-11-12 19:45:23

标签: java concurrenthashmap

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfAbsent-K-java.util.function.Function-

假设我们有10个线程使用不同的键值调用以下代码。提供给computeIfAbsent方法的“函数”参数是并行运行的,还是computeIfAbsent将“锁定”整个表?

Map<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, K -> { // long time operation });

1 个答案:

答案 0 :(得分:2)

有两种解释问题的方法。

第一个是,从理论上讲,ConcurrentHashMap.computeIfAbsent方法的规范是否保证仅在要计算的特定键上进行同步?答案直接来自the documentation for the method

  

在计算进行过程中,可能会阻止其他线程对该映射进行某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。

对于在整个映射还是仅在单个键上进行同步,这是模棱两可的,但是它没有明确保证在计算缺少值时,其他键上的更新可以在其他线程中进行。它说“某些尝试进行的更新操作” 可能被阻止,但并没有限制被阻止的次数。因此,严格的答案是:,允许使用符合标准的实现在整个地图对象上进行同步,并阻止所有其他更新。


问题的第二种解释实际上是方法的实现是否仅在单个键上同步?答案将取决于哪个实现,但是将来自该实现的源代码。

来自the OpenJDK 8 implementation

Node<K,V> f;
// ...
if(/* ... */) {
    // ...
} /* ... */ else if(/* ... */) {
    Node<K,V> r = new ReservationNode<K,V>();
    synchronized (r) {
        // ...
    }
    // ...
} /* ... */ else {
    // ...
    synchronized (f) {
        // ...
    }
    // ...
}

因此答案(至少在使用此实现的情况下)为,实际上,该方法在表示(fr的对象上同步一个单独的键/值对,而不是整个映射,因此在计算函数时,不应阻止对其他键的更新。