我有一个与Java线程活动锁相关的有趣问题。这就对了。
有四个全局锁- L1、L2、L3、L4
有四个线程- T1、T2、T3、T4
T1需要锁定L1,L2,L3 T2需要锁定L2 T3需要锁定L3,L4 T4需要锁定L1,L2
因此,问题的模式是-任何线程都可以以任何顺序运行和获取锁。如果任何一个线程检测到它需要的锁不可用,它会释放它之前获得的所有其他锁,等待一段固定时间后再重试。该循环重复,从而导致活动锁定条件。
因此,为了解决这个问题,我有两个解决方案
1)让每个线程随机等待一段时间后再重试。
OR,2)让每个线程以特定的顺序获取所有锁(即使线程不需要所有锁)
我不相信这是我唯一的两个选择。请给我建议。
发布于 2013-04-22 23:33:55
让所有线程在需要时进入一个受互斥锁保护的状态机,然后释放它们的锁。线程应该公开返回它们需要的锁集的方法,以便继续,并发出信号/等待私有信号量信号。SM应该为每个锁包含一个布尔值和一个“等待”队列/数组/向量/列表/任何容器来存储等待线程。
如果线程进入SM互斥锁来获取锁,并且可以立即获得锁设置,则它可以重置其布尔集,退出互斥锁并继续。
如果一个线程进入SM互斥体并且不能立即获得它的锁设置,它应该把自己添加到'Waiting',退出互斥体并等待它的私有信号量。
如果一个线程进入SM互斥锁来释放它的锁,它将锁bools设置为“返回”它的锁,并迭代“等待”,试图找到一个现在可以使用可用的锁集运行的线程。如果找到一个,它会适当地重置bools,从“等待”中删除找到的线程,并向“找到”的线程信号量发出信号。然后它退出互斥锁。
您可以随意调整用于匹配可用的set lock bools和等待线程的算法。也许您应该释放需要最大匹配集的线程,或者您可能想要“轮换”“等待”容器元素以减少饥饿。你说了算。
像这样的解决方案不需要轮询(其性能消耗CPU使用率和延迟),也不需要持续获取/释放多个锁。
使用OO设计来开发这样的方案要容易得多。用于发出信号/等待信号量并返回所需锁集合的方法/成员函数通常可以填充在线程类继承链中的某个位置。
发布于 2013-04-22 22:21:54
除非有充分的理由(性能方面的)不这样做,否则我会将所有锁统一到一个锁对象中。这与您建议的解决方案2类似,只是在我看来更简单。
顺便说一句,这个解决方案不仅更简单,错误更少,而且性能可能比您建议的解决方案1更好。
发布于 2013-04-22 22:24:53
就我个人而言,我从未听说过选项1,但我绝不是多线程方面的专家。仔细考虑之后,它听起来会工作得很好。
然而,处理线程和资源锁定的标准方法与选项2有些关系。为了防止死锁,需要始终以相同的顺序获取资源。例如,如果您总是以相同的顺序锁定资源,则不会有任何问题。
https://stackoverflow.com/questions/16149430
复制相似问题