java - 从多个线程以相反顺序执行 equals() 时 Java 同步集合的问题

标签 java collections deadlock

示例场景:

  • 创建两个 SynchronizedSet(s1 和 s2)
  • 将它们传递给两个线程(T1 和 T2)
  • 启动线程

T1 的 run() : 而(永远) s1.等于(s2)

T2 的 run() : 而(永远) s2.等于(s1)

会发生什么? - SynchronizedSet 的 equals 获取自身的锁

  • 它计算传入的参数的长度以及它包含的内容以确定它是否相等[注意:这是基于我分析的日志的猜测]

  • 如果传入的参数也是 SynchronizedSet,调用 size() 和 containAll() 意味着也必须获取它的锁。

  • 上述例子中,T1和T2的锁获取顺序如下:

    T1: s1 -> s2 T2: s2 -> s1

当然,这会导致死锁。

此问题并非仅针对同步集合。即使使用 Hashtable 或 Vector 也可能发生这种情况。

我认为这是 Java API 限制(设计)。如何克服这个?我如何确保在我的应用程序中不会发生这种情况?在不陷入这种情况的情况下,我应该遵循一些设计原则吗?

最佳答案

I believe this is a Java API limitation (design).

我相信你错了。我曾经使用过的每个 PL 级锁定方案的基本要求是线程必须以相同的顺序锁定资源,否则就有死锁的风险。这也适用于数据库。

事实上,我认为您可以避免这种情况的唯一方法是:

  • 要求应用程序在单个原子操作中获取它需要的所有锁,或者
  • 使用单个全局锁进行所有锁定。

这两种方法都是不切实际且不可扩展的。

How to overcome this?

编写您的应用程序,以便所有线程以相同的顺序获取锁。 @Maurice 和@Nettogrof 的回答给出了如何执行此操作的示例,但如果您有很多集合需要担心,这可能会更加困难。

关于java - 从多个线程以相反顺序执行 equals() 时 Java 同步集合的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1552908/

相关文章:

java - 客户端-服务器应用程序套接字问题

java - 调整大小后 JLabel 文本在 JPanel 中消失

java - 为什么 Calendar.setTimeZone() 不会影响从数据库检索的日期

.net - .NET 2 中的唯一列表<T>

java - ArrayList不打印重复项(Java)

java - 在 Java 多线程中使用 Timeout 避免死锁

java - 当子字符串包含某些字符时更改整个字符串

java - hibernate ,从集合中删除

multithreading - 如果可以动态获取锁,则强加锁顺序并不能保证防止死锁。这是什么意思?

sql-server - 进程成为死锁受害者的原因