Java ConcurrentHashMap computeIfAbsent() 方法是否支持基于键的"locking"?
Does Java ConcurrentHashMap computeIfAbsent() method support key-based "locking"?
假设我们有10个线程使用不同的键值调用以下代码。 "Function" 参数是否并行提供给 computeIfAbsent 方法 运行,或者 computeIfAbsent 将 "lock" 整个 table?
Map<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, K -> { // long time operation });
有两种解释问题的方法。
首先是,从理论上讲,ConcurrentHashMap.computeIfAbsent
方法的 规范 是否保证仅在正在计算的特定密钥上同步?答案直接来自 the documentation for the method:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.
这对于它是在整个地图上同步还是仅在单个键上同步是不明确的,但它没有明确承诺在计算 value-if-absent 时可以在其他线程中对其他键进行更新。它说 "some attempted update operations" 可能会被阻止,但不会限制被阻止的内容或数量。所以严格的答案是,否,允许符合规范的实现在整个地图对象上同步,并阻止所有其他更新。
问题的第二种解释是,实际上,方法的实现是否仅在单个键上同步?对此的答案将取决于哪个实现,但将来自该实现的源代码。
来自the OpenJDK 8 implementation:
Node<K,V> f;
// ...
if(/* ... */) {
// ...
} /* ... */ else if(/* ... */) {
Node<K,V> r = new ReservationNode<K,V>();
synchronized (r) {
// ...
}
// ...
} /* ... */ else {
// ...
synchronized (f) {
// ...
}
// ...
}
所以答案(至少如果你正在使用这个实现)是是,在实践中,该方法在对象上同步(f
或 r
) 表示单个 key/value 对,而不是整个映射,因此在计算函数时不应阻止对其他键的更新。
假设我们有10个线程使用不同的键值调用以下代码。 "Function" 参数是否并行提供给 computeIfAbsent 方法 运行,或者 computeIfAbsent 将 "lock" 整个 table?
Map<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, K -> { // long time operation });
有两种解释问题的方法。
首先是,从理论上讲,ConcurrentHashMap.computeIfAbsent
方法的 规范 是否保证仅在正在计算的特定密钥上同步?答案直接来自 the documentation for the method:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.
这对于它是在整个地图上同步还是仅在单个键上同步是不明确的,但它没有明确承诺在计算 value-if-absent 时可以在其他线程中对其他键进行更新。它说 "some attempted update operations" 可能会被阻止,但不会限制被阻止的内容或数量。所以严格的答案是,否,允许符合规范的实现在整个地图对象上同步,并阻止所有其他更新。
问题的第二种解释是,实际上,方法的实现是否仅在单个键上同步?对此的答案将取决于哪个实现,但将来自该实现的源代码。
来自the OpenJDK 8 implementation:
Node<K,V> f;
// ...
if(/* ... */) {
// ...
} /* ... */ else if(/* ... */) {
Node<K,V> r = new ReservationNode<K,V>();
synchronized (r) {
// ...
}
// ...
} /* ... */ else {
// ...
synchronized (f) {
// ...
}
// ...
}
所以答案(至少如果你正在使用这个实现)是是,在实践中,该方法在对象上同步(f
或 r
) 表示单个 key/value 对,而不是整个映射,因此在计算函数时不应阻止对其他键的更新。