Java 解决获取多个锁时的死锁问题

Java 解决获取多个锁时的死锁问题,java,multithreading,concurrency,locking,deadlock,Java,Multithreading,Concurrency,Locking,Deadlock,例如,我有多个线程T1、T2、T3和T4。T1有资源A,T2有资源B,T3有资源A、B和C,T4有资源B和C 当T1出现时,它锁定A并执行一些工作 然后T2来了,它锁定B并做一些工作 下一个是T3,它锁定在C上,但等待A(因为A还没有被获取,所以还没有B) 最后,T4在此等待B(由于B尚未获取,因此尚未等待C) 伪代码如下所示: for all resources needed { // in case of T3, they are A and B acquire lock on r

例如,我有多个线程T1、T2、T3和T4。T1有资源A,T2有资源B,T3有资源A、B和C,T4有资源B和C

当T1出现时,它锁定A并执行一些工作

然后T2来了,它锁定B并做一些工作

下一个是T3,它锁定在C上,但等待A(因为A还没有被获取,所以还没有B)

最后,T4在此等待B(由于B尚未获取,因此尚未等待C)

伪代码如下所示:

for all resources needed {  // in case of T3, they are A and B
    acquire lock on resource;  // acquiring lock one after one
}
现在,如果T2完成并释放B上的锁,T4将被唤醒以锁定B。但它仍然需要等待C。因此,现在T4保持B并等待C

死锁发生在T1完成并释放A上的锁时,T3被唤醒以锁定A。但它仍然需要等待B。T3现在持有A和C并等待B。然后我让T3和T4进入无限等待

要解决此问题,我的伪代码更改为:

while not all resource locks obtained {  // in case of T3, they are A and B
    try to lock on resource;  // immediate return success or fail
    if fail, release all unsecured locks; // in case of T3, C is secured,
                                          // so only A and B may be released,
                                          // in case of T4, both B and C may be released
}
更改后的代码可以工作,但在我的测试中,我可以看到T3和T4不断地检查锁,总体而言,由于while循环,程序运行较慢

然后我对代码做了一个小改动:

while not all resource locks obtained {
    try for 1 second to lock on resource;  // return after 1 second if fail
    if fail, release all unsecured locks;
}
这一微小的变化使得锁的检查频率降低,程序运行速度也比以前更快


我不喜欢我现在拥有的,因为它似乎不是最优的,而且在达到预期效果之前效果是随机的。有没有更好的方法来解决上面提到的死锁情况,或者我应该只解决现在的问题?

防止死锁很简单:

  • 切勿升级锁,例如将读锁升级为写锁
  • 始终以相同的顺序获取锁

  • 你不是在做第二件事。您只是随机尝试获取锁-当然这是低效的

    防止死锁很简单:

  • 切勿升级锁,例如将读锁升级为写锁
  • 始终以相同的顺序获取锁

  • 你不是在做第二件事。您只是随机尝试获取锁-当然这是低效的

    任何真正死锁的解决方案都是以相同的顺序获取锁。无需休眠或重试。

    任何真正死锁的解决方案都是以相同的顺序获取锁。无需睡眠或重试。

    @EJP这没有错,只是,嗯,故意低调了。:-)吞吐量为零的技术既没有效率也没有效率:它是错误的。如果你想开个玩笑,你没有成功。@EJP吞吐量为零的技术既没有效率也没有效率:它是错误的。根据OP的评论:“这一微小的变化使得锁的检查频率降低,程序运行速度也比以前更快。”显然吞吐量不是零。事实上,你可以说OP评论的更改使他的代码更加高效,而且很可能更好的锁定方案会使代码更加高效。如果你想说明一点……我可以让程序单线程运行,以避免使用锁……@AndrewHenle死锁应用程序的吞吐量为零。如果不是零,他就不会陷入僵局,问题的前提是错误的。这不是第一次了。很多人错误地使用“死锁”来表示“锁定”。@EJP这没有错,只是,嗯,故意低估了。:-)吞吐量为零的技术既没有效率也没有效率:它是错误的。如果你想开个玩笑,你没有成功。@EJP吞吐量为零的技术既没有效率也没有效率:它是错误的。根据OP的评论:“这一微小的变化使得锁的检查频率降低,程序运行速度也比以前更快。”显然吞吐量不是零。事实上,你可以说OP评论的更改使他的代码更加高效,而且很可能更好的锁定方案会使代码更加高效。如果你想说明一点……我可以让程序单线程运行,以避免使用锁……@AndrewHenle死锁应用程序的吞吐量为零。如果不是零,他就不会陷入僵局,问题的前提是错误的。这不是第一次了。许多人错误地使用“死锁”来表示“锁”。@user1589188,有些人编写的代码中,两个或多个线程被共享数据结构及其伴随的锁紧密耦合,以至于无法比单线程程序更快(甚至更快)地工作。打破这种紧密耦合取决于程序的设计者——找到方法让线程尽可能独立地运行。@user1589188不是:例如,不是每个线程都可以获得每个锁,但无论如何,这是避免死锁的唯一方法,因此,没有任何有效的方法可以与之相比。@EJP我的上一个伪代码确实解决了我的死锁问题,尽管效率很低,所以我的问题是在单线程和定期检查之间有没有更好的方法。@user1589188,有些人编写的代码中,两个或多个线程被共享数据结构及其伴随的锁紧密耦合,无法比单线程程序更快(甚至更快)工作。打破这种紧密耦合取决于程序的设计者——找到方法让线程尽可能独立地运行。@user1589188不是:例如,不是每个线程都可以获得每个锁,但无论如何,这是避免死锁的唯一方法,所以没有什么可以与之比较的。@EJP我的上一个伪代码确实解决了我的死锁问题,尽管效率很低,所以我的问题是在单线程和定期检查之间有没有更好的方法。