示例场景:
- 创建两个 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/