java - Java ConcurrentHashMap computeIfAbsent() 方法是否支持基于键的“锁定”?
问题描述
假设我们有 10 个线程使用不同的键值调用以下代码。提供给 computeIfAbsent 方法的“函数”参数是否并行运行,或者 computeIfAbsent 将“锁定”整个表?
Map<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, K -> { // long time operation });
解决方案
有两种方法可以解释这个问题。
首先是,理论上,该方法的规范ConcurrentHashMap.computeIfAbsent
是否保证仅在正在计算的特定键上同步?答案直接来自该方法的文档:
在计算过程中,其他线程对该映射的某些尝试更新操作可能会被阻塞,因此计算应该简短而简单,并且不得尝试更新该映射的任何其他映射。
这对于它是在整个映射上同步还是在单个键上同步是模棱两可的,但它没有明确承诺在计算 value-if-absent 时其他键上的更新可以在其他线程中进行。它说“一些尝试的更新操作”可能会被阻止,但不会对被阻止的数量或数量施加限制。因此,严格的答案是,不,允许一致的实现在整个地图对象上同步,并阻止所有其他更新。
问题的第二种解释是,实际上,该方法的实现是否仅在单个键上同步?对此的答案将取决于哪个实现,但将来自该实现的源代码。
Node<K,V> f;
// ...
if(/* ... */) {
// ...
} /* ... */ else if(/* ... */) {
Node<K,V> r = new ReservationNode<K,V>();
synchronized (r) {
// ...
}
// ...
} /* ... */ else {
// ...
synchronized (f) {
// ...
}
// ...
}
所以答案(至少如果你正在使用这个实现)是肯定的,实际上该方法在表示单个键/值对的对象(f
或r
)上同步,而不是整个映射,因此不应该更新其他键在计算函数时被阻塞。
推荐阅读
- java - 我应该保持数据库连接打开以处理每个请求吗?以及如何以正确的方式做到这一点
- c# - 将数据表分配为 tabitem.content 时获取 System.Data.DataRows 而不是实际值
- docker - 基于节点的 Docker 映像中缺少 Oracle 客户端库
- javascript - 在三元检查对象是否未定义之前,react 会为未定义的对象抛出类型错误
- azure - 使用 Nativescript Core 将图像上传到 Azure 博客
- ruby - rbenv 安装 2.2.1 构建失败 Ubuntu 16.04
- android - OAuth 2 客户端 ID 重复问题
- ruby-on-rails - 在生产中通过浏览器连接到应用程序地址
- sql - SQL 子字符串 charindex
- spring-rabbit - 使用带有rabbit mq流的spring cloud任务时出错