Java同步块使用方法调用来获取同步对象

2024-01-02

我们正在编写一些锁定代码,并遇到了一个特殊的问题。我们使用 ConcurrentHashMap 来获取我们锁定的对象实例。所以我们的同步块看起来像这样

synchronized(locks.get(key)) { ... }

我们重写了 ConcurrentHashMap 的 get 方法,使其在不包含键的情况下始终返回一个新对象。

@Override
public Object get(Object key) {
   Object o = super.get(key);
   if (null == o) {
      Object no = new Object();
      o = putIfAbsent((K) key, no);
      if (null == o) {
         o = no;
      }
   }
   return o;
}

但是有没有一种状态,get方法已经返回了对象,但是线程还没有进入synchronized块。允许其他线程获取相同的对象并锁定它。

我们有一个潜在的竞争条件是

  • 线程1:获取key为A的对象,但不进入synchronized块
  • 线程2:获取带有键A的对象​​,进入同步块
  • 线程2:从映射中删除对象,退出同步块
  • 线程1:进入同步块,对象不再在map中
  • 线程 3:获取键 A 的新对象(与线程 1 获取的对象不同)
  • 线程 3:进入同步块,而线程 1 也在其同步块中,两者都使用键 A

如果 java 在 get 调用返回后直接进入同步块,则不会出现这种情况。如果没有,是否有人对我们如何删除密钥而不必担心这种竞争条件有任何意见?


在我看来,问题源于你锁定了映射值,而实际上您需要锁定key(或者它的一些派生)。如果我理解正确的话,您希望避免 2 个线程使用相同的键运行关键部分。

你可以锁定钥匙吗?你能保证你总是使用同一个密钥实例吗?

一个不错的选择:

根本不要删除锁。用一个参考图 http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/ReferenceMap.html价值观较弱。这样,只有当当前没有任何线程使用映射条目时,才会删除该条目。

Note:

1) 现在您必须同步此映射(使用 Collections.synchronizedMap(..))。

2)您还需要同步为给定键生成/返回值的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java同步块使用方法调用来获取同步对象 的相关文章

随机推荐

  • 使用 C# 中的架构进行 XML 解析

    我正在编写一些在运行时加载 xml 文件的代码 目前 我们使用 XmlDocument 类型来读取 xml 文件 并在 SelectSingleNode 语句周围包装一个 try catch 这是在节点为 null 或在我们解析用户时不存在
  • iOS 从后台重新检查加载位置

    我正在构建一个应用程序 它根据您当前的位置显示结果数据 目前 我正在使用viewDidLoad的方法UIViewController开始CLLocationManager并获取当前位置 一旦我获得了与我想要的准确性相匹配的位置 我就会向我的
  • 从发布的 JSON 获取经典 ASP 变量

    我正在尝试通过 AJAX 将 JSON 发布到经典 ASP 页面 该页面检索值 检查数据库并将 JSON 返回到原始页面 我可以通过 AJAX 发布 JSON 我可以从 ASP 返回 JSON 我无法将发布的 JSON 检索到 ASP 变量
  • 在 Golang 中导入 C 错误:cc1.exe:错误:给出的文件名太多

    我正在尝试导入并使用 C 包 但我不断收到此错误 runtime cgo cc1 exe error too many filenames given Type cc1 exe help for usage cc1 exe fatal er
  • 将域指向我的远程 Node JS 应用程序?

    我正在尝试弄清楚如何在我的 Ubuntu 10 04 LTS 服务器上准确部署 Node JS 我读过许多不同的博客和文章 它们解释了多种不同的方式 大多数似乎已经过时了 或者看起来并没有真正发挥作用 看来最简单的解决办法就是使用Forev
  • 部分类文件的命名约定

    我正在生成大部分 ASP NET MVC 脚手架代码 所有生成的文件都是使用标准命名约定的部分类 例如 我的员工控制器文件名为 EmployeeController cs 如果我希望使用自定义的非生成逻辑扩展 EmployeeControl
  • Visual Studio 2019:起始页而不是起始窗口

    Visual Studio引入了阻塞Start Window而不是非阻塞Start Page 考虑到Visual Studio的可扩展性如何 有没有办法让VS2019显示非阻塞Start Page The new Start Window非
  • switch 语句:“期望一个常量值”

    目前我正在与 神奇的字符串 问题作斗争 public class MyDataField class definition exuecuted method public void SwitchMultipleDataFields var
  • 如何将三个sql选择组合成一个查询

    我有下面的三个查询 我想将它们合并为一个查询 这样我就可以得到三列 其中包含按县划分的结果 我尝试对所有表进行内部联接 但得到的数据很差 如何组合这三个查询并按县分组 select Total DLL Children SUM cd Num
  • java中通过反射设置对象字段的值

    首先 我有一个这样的对象 public class Entity public int data1 public String data2 public float data3 public SubEntity data4 public c
  • 如何将字节转换为字符串?

    我需要转换我的Byte to a String because NSInteger write const uint8 t buffer maxLength NSUInteger takes a String作为它的第一个参数 我想要的是
  • 需要 root 才能在运行时通过应用程序执行 shell 命令“输入 keyevent <#>”?

    我正在尝试执行 adb shell 命令input keyevent 5在运行时通过我的应用程序接听电话 如果我这样做 Runtime getRuntime exec input keyevent 5 它似乎没有执行 什么也没有发生 但是当
  • 如何在 Azure DevOps 中从 .vdproj 构建安装项目?

    我最近将一些 Windows 应用程序升级到 VS2019 并使用 VS2019 中的 VSInstallerProject 扩展创建了安装项目 我注意到 运行发布管道时 安装程 序并未创建 但我需要此处的 msi 或 exe 文件 以便我
  • Gradle 无法解析来自神器的依赖关系

    我正在尝试构建一个 android library MyLib1 它依赖于 gradle 和 jenkins 中的另一个 android library MyLib2 我有点绝望 因为我认为我的 gradle 文件和设置都没有问题 我成功地
  • Jetpack Compose LazyColumn - 如何分别更新每个项目的值?

    我正在为我的应用程序开发购物车功能 我希望分别添加 减少 LazyColumn 中每个列表项的数量 我只使用一个 记住 因此如果我单击添加 减少 它们都会同时更新 如何单独控制每个项目 截屏 https i stack imgur com
  • 将 TypeScript 转换为 JavaScript

    我想知道如何才能改变打字稿 http www typescriptlang org 以跨平台方式转换为 JavaScript 我知道以下内容的可用性Typescript 的节点包管理器 http www typescriptlang org
  • Hibernate - 通过用户名关系进行加密引用

    我想知道我的想法是否可以用休眠来实现 我想要的是有一个包含用户名的表 并且每个引用该表的表都将用户名加密在一列中 因此 用户名不是以普通文本形式存在 而是在每个引用用户表的表中加密 所以我需要类似的东西 ManyToOne JoinColu
  • 如何使 Visual Studio 始终在 git 更改的新选项卡中查看提交详细信息?

    它在 git 历史记录中的一个小窗口中打开提交详细信息 这非常不方便 因为它太小了 看不到任何东西 每次点击 在新选项卡中打开 很烦人 有没有办法让 Visual Studio 始终在新选项卡中打开它 目前无法直接在新选项卡中打开 提交详细
  • 应用了 Hilt Android Gradle 插件,但未找到 com.google.dagger:hilt-android-compiler 依赖项

    我收到错误 Hilt Android Gradle 插件已应用 但没有com google dagger hilt android compiler发现了依赖关系 在构建项目时 以下是我如何将柄添加到我的项目中 我猜你缺少这种依赖 kapt
  • Java同步块使用方法调用来获取同步对象

    我们正在编写一些锁定代码 并遇到了一个特殊的问题 我们使用 ConcurrentHashMap 来获取我们锁定的对象实例 所以我们的同步块看起来像这样 synchronized locks get key 我们重写了 ConcurrentH