如何使用NetBeans消除Java代码中的死锁

如何使用NetBeans消除Java代码中的死锁,java,multithreading,deadlock,Java,Multithreading,Deadlock,我有Java的旧代码,它会死锁。。。我从未将netbeans用作开发工具。。。但是,我需要修复代码 我以调试模式运行应用程序,单击检查死锁,netBeans显示一个屏幕。四分之二的线是红色的。。。请参阅下面的屏幕转储 我是多线程新手,最重要的不是我的代码 最有可能导致问题的原因是什么 据我所知,问题很可能与多线程获取和释放锁的方式(或者更具体地说是顺序)有关。 在上面的示例中,两个线程需要访问两个锁(或监视器): nano.toolbox.strategies.ESMarketMaker na

我有Java的旧代码,它会死锁。。。我从未将netbeans用作开发工具。。。但是,我需要修复代码

我以调试模式运行应用程序,单击检查死锁,netBeans显示一个屏幕。四分之二的线是红色的。。。请参阅下面的屏幕转储

我是多线程新手,最重要的不是我的代码

最有可能导致问题的原因是什么


据我所知,问题很可能与多线程获取和释放锁的方式(或者更具体地说是顺序)有关。 在上面的示例中,两个线程需要访问两个锁(或监视器):

  • nano.toolbox.strategies.ESMarketMaker
  • nano.toolbox.strategies.ExecutionManager
从当前处于死锁的两个线程上的堆栈跟踪中,我们可以看到线程“ExecutionManager”已获取ExecutionManager监视器,但正在等待获取“ESMarketMaker”监视器(同时仍持有“ExecutionManager”监视器)

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

这是死锁的一个类示例,以及获取锁的顺序可能导致死锁的许多方式

解决这类问题的方法有很多:

  • 如果可能,所有需要一组锁来操作的线程都必须以相同的顺序获取共享锁(上述死锁中的问题是相反的顺序)。但这并不总是可能的,因为在不同的条件下,多个线程可能只有半重叠的锁使用,因此设计一个能够确保统一排序的获取协议可能很困难或不可能
  • 您也可以使用tryLock(),这是一种非阻塞采集,它返回一个标志以指示成功或失败,并提供在重试之前执行其他操作的选项。在这种情况下,我建议的一件事是,如果获取失败,则删除所有当前拥有的锁,然后重新尝试(从而让位于当前线程持有的任何或所有锁上的任何人完成其工作,可能在重试时释放此线程所需的锁)
但需要注意的是,有时在决定使用何种协议时,需要对锁进行更明确的控制,而不是Java中的正常同步。在这些情况下,使用显式ReentrantLock实例可能是一个好处,因为这允许您执行诸如检查锁是否已解锁或当前已锁定之类的操作,并执行如上所述的非阻塞尝试锁

我希望这能有所帮助,很抱歉我不能说得更具体一些,但我需要查看这方面的源代码。:-)


(哦,顺便说一句,如果死锁是必须不惜一切代价避免的事情,那么第三件事是研究建模工具,根据程序和锁的状态对状态机进行建模,这可以与分析工具一起使用,分析工具可以检查模型中可能存在的死锁,如果发现任何死锁,请给出示例).

+1…但我不同意关于释放锁和重新获取锁的部分。如果两个代理做同样的事情,那么他们很可能会遇到一个活锁。本质上,两个代理不断地获取第一个锁,无法获取第二个锁,释放第一个锁并不断重复这个过程。当然,这是真的,这样的一个co假设在理论上是可能的,因此应该谨慎使用该解决方案,因为它不是防弹的。尽管如此,我怀疑,这种调度(在现实生活中)不太可能不说不存在,因为它需要对“错误”交错无限期地进行一致的调度。人们可以称之为“解决方案”乐观的是,它依赖于调度器的伪随机行为来确保(给定无限时间)“正确”在某一点上尝试交错。如果事先准确知道执行操作所需的锁,可能更好的解决方案是在每次重试时尝试以伪随机顺序获取这些锁,直到获取所有锁为止,这种随机性与非阻塞获取相结合肯定会(给定无限期)确保线程在某个时刻可以获得所有必需的锁。