在java中以原子方式获取多个锁

2024-05-15

我有以下代码: 注意:为了可读性,我尽可能简化了代码。 如果我忘记了任何关键部分,请告诉我。

public class User(){

    private Relations relations;

    public User(){
        relations = new Relations(this);
    }   

    public getRelations(){
        return relations;
    }
}


public class Relations(){

    private User user;

    public Relations(User user){
        this.user = user;
    }

    public synchronized void setRelation(User user2){
        Relations relations2 = user2.getRelations();

        synchronized(relations2){

            storeRelation(user2);

            if(!relations2.hasRelation(user))
                relations2.setRelation(user);
        }
    }   

    public synchronized boolean hasRelation(User user2){
        ... // Checks if this relation is present in some kind of collection
    }

    /*Store this relation, unless it is already present*/
    private void storeRelation(User user2){
        ... // Stores this relation in some kind of collection
    }
}

此实现应确保对于所有关系 x, y:

x.user = u_x
y.user = u_y

以下不变量成立:

x.hasRelation( u_y ) <=> y.hasRelation( u_x )

我相信这适用于上述代码吗?

注意:它当然在 setRelation(..) 执行期间不成立, 但在那一刻,所涉及的两种关系都被锁定了 由执行线程持有,因此其他线程无法读取 涉及的关系之一的 hasRelation(..) 。

假设这种情况成立,我相信仍然存在潜在的僵局风险。 那是对的吗?如果是的话,我该如何解决? 我想我需要以某种方式原子地获取 setRelation(..) 中的两个锁。


你在这两点上都是正确的:你的不变量确实成立(假设我正确理解你的方法名称的含义等等,并假设通过if(!relations.hasRelation(user)) relations2.setRelation(user2);你本来想写if(!relations2.hasRelation(user)) relations2.setRelation(user);),但是确实存在死锁的风险:如果一个线程需要获得一个锁x然后继续y,另一个线程需要获得锁y然后继续x,那么存在每个线程都会成功获取其值的风险first锁定,从而防止对方获得它的second lock.

一种解决方案是强制执行严格的通用顺序来获取锁Relations实例。你所做的是添加一个常量整数字段lockOrder:

private final int lockOrder;

和一个静态整数字段currentLockOrder:

private static int currentLockOrder = 0;

每次你创建一个Relations实例,你设置它的lockOrder到当前值currentLockOrder,增量表示:

public Relations()
{
    synchronized(Relations.class) // a lock on currentLockOrder
    {
        lockOrder = currentLockOrder;
        ++currentLockOrder;
    }
}

这样每个实例Relations将具有独特的、不可变的价值lockOrder. Your setRelation然后方法将按指定的顺序获取锁:

public void setRelation(final User thatUser)
{
    final Relations that = thatUser.getRelations();

    synchronized(lockOrder < that.lockOrder ? this : that)
    {
        synchronized(lockOrder < that.lockOrder ? that : this)
        {
            storeRelation(thatUser);

            if(! that.hasRelation(user))
                that.storeRelation(user);
        }
    }
}

从而确保如果两个线程都需要获得两个线程的锁x and y,那么他们要么首先获得锁定x,或者他们都会首先获得锁定y。无论哪种方式,都不会发生僵局。

顺便说一句,请注意,我改变了setRelation to storeRelation. setRelation可以,但是为什么要增加这种复杂性呢?

另外,还有一件事我不明白:怎么会这样?x.setRelation(u_y) calls x.storeRelation(u_y) 无条件地,但调用y.setRelation(u_x) (or y.storeRelation(u_x)) 除非y还没有建立关系吗?这没有道理。似乎要么both需要检查,或者neither查克群岛。 (没有看到实施Relations.storeRelation(...),我无法猜测是哪一种情况。)

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

在java中以原子方式获取多个锁 的相关文章

随机推荐

  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • Elastic Search 索引经常被删除[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在 google cloud 上对个人项目运行弹性搜索 并将其用作我的应用程序的搜索索引 从最近三天开始 索引就被神秘地删除了 我不知
  • Hibernate 本机查询 - char(3) 列

    我在 Oracle 中有一个表 其中列 SC CUR CODE 是 CHAR 3 当我做 Query q2 em createNativeQuery select sc cur code sc amount from sector cost
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • 带有 `:hover` 和多个相邻兄弟选择器的 Webkit 错误

    Safari 和 Chrome 以及 Opera 和 Firefox 都可以处理 hover伪类和相邻兄弟选择器 a hover div 这有效 但是 当添加另一个相邻兄弟时 div hover a div Webkit 崩溃了 但是 如果
  • 列表过滤器内的 Java 8 lambda 列表

    示例 JSON id 1 products id 333 status Active id 222 status Inactive id 111 status Active id 2 products id 6 status Active
  • 快速钥匙串更新只有在第二次尝试时才起作用

    您好 我在更新存储在钥匙串中的登录信息方面遇到了 iOS 钥匙串的一个非常奇怪的问题 因此 如果没有保存的凭据 则正确运行保存函数会保存登录信息 如果登录信息已存在并且用户更新了密码 则更新功能仅正确更新密码 但是 如果登录信息存在并且我尝
  • 在另一个插件中覆盖插件 GSP 和控制器

    我的项目中有一个相当复杂的 grails 插件依赖结构 并且在覆盖安全插件中的类时遇到问题 我的结构有点像这样 Web App Audit Plugin Spring Security Core Plugin Security Wrappe
  • Ruby 枚举器中的“break”与“raise StopIteration”

    如果我使用 Ruby Enumerators 来实现生成器和过滤器 generator Enumerator new do y x 0 loop do y lt lt x x 1 break if x gt CUTOFF end end l
  • 在 jQuery 中绑定元素及其子元素

    我想将事件绑定到元素及其子元素 做这个的最好方式是什么 element bind click function event doSomething element bind click function event doSomething
  • 如何有效地找到距给定点最远的点(从一组点中)?

    我正在寻找一种算法或数据结构来解决以下问题 给你一组点 S 然后你会得到另一个点形式的 Q 查询 对于每个查询 找到集合中距离给定点最远的点 集合中最多有 10 5 个点和 10 5 个查询 所有点的坐标都在 0 到 10 5 范围内 我想
  • 解组转义 XML

    在 Go 中 我将如何解码此 XML 响应 我尝试过建立一个自定义UnMarshal方法在我的Answerstruct 但我运气不太好
  • 如何上传文件 - sails.js

    我可以下载图像和 pdf 但无法下载文档文件 doc pptx odt 下载文档 doc pptx odt 时 仅将其下载为 ZIP XML 文件 我可以做什么 我在用着 填写上传文件文档 https github com balderda
  • 带有两个提交按钮的 GTM 和 asp.net Web 表单问题

    只是想分享使用 Google 跟踪代码管理器 GTM 和表单标签中的两个提交按钮 常见的遗留 asp net Webforms 技术 时的发现 GTM 供网站编辑使用 因此 当需要实现或跟踪其他脚本或事件时 开发人员不需要参与 问题是 GT
  • 使用 nib 作为带有 nib 类的表节标题

    我想创建一个加载 nib 文件并将其设置为标题 UIView 的节标题 这个 nib 文件还将有一个关联的类 其中插座和操作连接到 因此我想像平常一样使用 nib 加载该类 我在网上搜索并找到了几个类似的答案 但我找不到任何适合我的答案 经
  • 通过Java从MySQL中获取大量记录

    有一个 MySQL 表 服务器上的用户 它有 28 行和 100 万条记录 也可能会增加 我想从这个表中获取所有行 对它们进行一些操作 然后将它们添加到 MongoDB 中 我知道通过简单的 从用户中选择 操作来检索这些记录将花费大量时间
  • Google 地图 InfoBubble PixelOffset(从标记上方的默认位置移动)

    我正在尝试实现一个自定义 infoBubble 它的框打开到标记的侧面 而不是顶部的默认位置 事实证明这比预期的要困难 使用普通的infoWindow 您可以使用pixelOffset 请参阅此处文档 https developers go
  • 如何更改 Ubuntu 14.04 上的 php-cli 版本?

    我是 Linux 新手 在篡改时破坏了一些 php 设置 如果我执行一个包含以下内容的 php 脚本 phpinfo 它显示 php 版本为 5 6 但通过命令行 如果我运行php v它返回 7 0 版本 我想让两个版本匹配 我怎样才能修复
  • SQL中的三元运算符? “传递给 LEFT 或 SUBSTRING 函数的长度参数无效”

    抱歉这个误导性的话题 我不知道如何更好地表达 因为我主要是一名软件开发人员 所以我想到了三元运算符并解决了以下问题 我需要找到通过可为空的外键链接两个表的最可靠的方法 modModel and tabSparePart 两者之间唯一的相似之
  • 在java中以原子方式获取多个锁

    我有以下代码 注意 为了可读性 我尽可能简化了代码 如果我忘记了任何关键部分 请告诉我 public class User private Relations relations public User relations new Rela