2010-10-19 59 views
3

我有Java中的旧代码,它会死锁...我从来没有使用netbeans作为开发工具...但是,我需要修复代码。如何使用NetBeans删除Java代码中的死锁

我在调试模式下运行应用程序,点击检查死锁,netBeans带来了一个屏幕。四个线程中的两个线程处于红色状态......请参阅下面的屏幕转储。

我新的多线程,并在该代码的顶部是不是我的......

什么是最有可能造成问题的原因?

alt text

回答

5

至于我可以告诉这个问题很可能与中(或者更具体的顺序)的多个线程获取和释放锁的方式。 在上述例子中的两个线程需要访问两个锁(或监视器):

  • nano.toolbox.strategies.ESMarketMaker
  • nano.toolbox.strategies.ExecutionManager

从堆跟踪当前处于死锁状态的两个线程,我们可以看到线程'ExecutionManager'获得了ExecutionManager监视器,但正在等待'ESMarketMaker'监视器正在等待获取(同时仍持有'ExecutionManager'监视器)。

另一方面,'StrategyManager'线程已经获得'ESMarketMaker'监视器,但正在等待'ExecutionManager'监视器的获取(同时仍持有'ESMarketMaker'监视器)。

这是一个死锁的类示例,以及获取锁的顺序会导致死锁的很多方法。

有解决这些类型的问题很多:

  • 如果可能的话,所有的线程需要一些船闸运行的,必须获得以相同的顺序共享锁(相逆的顺序问题在上述僵局中)。但是这并非总是可行的,因为多个线程在不同条件下可能只有半重叠的锁使用,为什么设计可以确保均匀排序的采集协议可能很难或不可能。
  • 您也可以使用tryLock()来代替它,这是一个非阻塞式获取,它会返回一个标志来指示成功或失败,并让您在重新尝试之前执行其他操作。在这种情况下,我会推荐的一件事是,如果获取失败,它将放弃所有当前拥有的锁,并再次从头开始尝试(因此让位于当前线程保留的任何或所有锁上的任何人完成其锁定工作,也许可以释放这个线程在重试时需要的锁)。

但有一点需要注意的是,有时候在决定使用协议时,需要更多地显式控制您的锁,而不是使用Java中的常规同步。在这些情况下,显式ReentrantLock实例的使用可以是一个好处,因为它们允许您执行诸如检查锁是否已解锁或当前已锁定等操作,并执行上述非阻塞try-lock。

我希望这可以帮助,我很抱歉,我不能更具体,但我需要看到源代码。:-)

(哦,ps,人们可能会选择的第三件事,如果死锁是所有成本都必须避免的事情,那就是研究建模工具,在程序状态上建模一个状态机和锁,它们可以与分析工具一起使用,分析工具可以检查这种模型中可能存在的死锁并给出示例,如果发现任何这样的情况)。

+2

+1 ...但我不同意释放锁和重新获取它们的部分。如果两个代理做同样的事情,那么他们可能会遇到一个活锁。基本上,两个代理不断获得第一个锁,未能获得第二个锁,释放第一个锁,并连续重复该过程。 – 2010-10-19 23:21:04

+0

这当然是对的,这样的条件在理论上是可行的,因此应该谨慎使用解决方案,因为它不是防弹的。尽管如此,我认为这样的调度(在现实生活中)不大可能不说不存在,因为它需要无限期地一致地调度“错误”的交错。有人可能称之为“解决方案”乐观,因为它依赖于调度器的伪随机行为来确保(在无限期的时间内)在某个点尝试“正确”交织。 – micdah 2010-10-19 23:35:37

+0

也许一个更好的解决方案,假设人们事先知道准确执行操作所需的锁,就是试图在每次重试时以伪随机顺序获取这些锁,直到获得所有锁,这种随机性与非阻塞获取相结合肯定会(给定无限期)确保线程在某个时刻可以获得所有需要的锁。 – micdah 2010-10-19 23:39:17