许多线程等待锁定一个对象,但没有线程持有该锁

时间:2014-02-12 08:51:06

标签: java multithreading

我有一个目前卡住的应用程序,我正在努力理解为什么。 在kill -3(线程转储)输出中,我看到许多线程等待锁定一个对象(具体来说 - 等待Vector的同步方法),但我没有看到任何线程持有该锁。

知道如何调试它?

由于

P.S。我知道Vector已经过时了,建议使用ArrayList,但这是我要调试的遗留代码。

2 个答案:

答案 0 :(得分:2)

您描述的情况听起来像是经典的死锁案例。

您可以(或许应该)使用Eclipse或IntelliJ Idea这样的IDE,通过它可以逐步调试应用程序并准确了解它停止的位置和操作。

或者,粘贴一些代码有助于澄清情况,并根据JVM版本等描述您的环境。

答案 1 :(得分:1)

可能的原因

以下问题通常会显示非常相似的症状(您的计划:

  • Deadlocks:对共享sressource的循环依赖
  • Live-Locks:处理资源锁定,但没有取得进展(前进一步,后退一步)
  • Resource starvation:做这项工作的人没有得到他所需要的东西。所有其他人似乎都很忙,但没有任何进展。
  • 大量交换:进度太慢,系统停止了
  • 线程太多(操作系统过载):系统完全忙于管理资源,所以没有时间做真正的工作

诊断工具

开发人员计算机上的调试器

死锁和类似问题通常很难重现,因此无法使用调试器轻松分析。问题通常发生在实时系统上,而不是在开发人员计算机上。原因可能是不同的工作负载,不同的数据星座甚至不同的操作系统或不同的硬件(更多的CPU核心,NUMA architecture等)。

远程调试器

您可以尝试使用remote debugger附加到生产系统。只有当您可以完全停止生产机器的风险时(例如,由于HVM崩溃!),您才应该这样做。您应该只在一对调试会话中执行此操作,并与对等方讨论每个步骤。

记录和可视化

使用过多的日志记录并可视化日志数据(R Studio,Mathematica等)。请注意,日志记录可能会更改您的系统。 Naive日志记录将根据性能和其他日志记录更改您的实时系统。在将日志记录部署到实时系统之前,请尝试asynchronous logging并测试日志记录对性能的影响。计划您希望如何可视化您的日志数据以及您希望看到的上述不同可能原因的内容。否则,您可能会错过一个可帮助您显示根本原因的日志语句。

REPL

通过引入“命令行”(REPL)来查询您的实时系统。通过向实时系统添加命令行,您可以查询它并更改其中的一部分以诊断根本原因。您可以使用Clojure REPLScala SBT REPLBean shell或使用JRebel添加实时更改以及外部触发器来运行交换代码(WebService,调度程序,消息队列,等等)。成对工作(在运行之前讨论每个命令)并记住保护REPL不受外部访问(在本地主机或Unix套接字上绑定,使用命名管道,仔细检查防火墙,使用公钥进行授权,记录每个访问权限)特殊日志等)!

JMX

通常,您可以使用Java Management Extensions(JMX)连接到正在运行的Java VM。使用JConsoleJava Visual VM,您可以检查每个线程的当前堆栈跟踪,并可以搜索死锁。此外,您可以在应用程序中部署自己的传感器使用DTrace(当您的系统支持此功能时,例如Solaris,FreeBSD,NetBSD,Mac OS X),您甚至可以监视操作系统的各个部分。

您可以通过提供MBeansMXBeans(更严格的打字,更好的兼容性)来添加自己的传感器。

诊断

死锁

JConsole和VisualVM都有一个函数来查找死锁并显示死锁中涉及的线程。与显示每个线程的当前堆栈跟踪的功能一起,诊断死锁变得轻而易举。

实时锁定和资源匮乏

当您在工作人员中添加计数器时,当工作人员获得锁定并且工作人员成功地取得实际进展时会增加计数器,如果您的应用程序取得进展或者哪些工作人员只是在没有工作的情况下工作,那么很容易找到实现任何目标。

您可以使用远程调试器,JMX(如果添加传感器),REPL或添加相应的日志消息来查询计数器。使用REPL或替换实时系统中的代码,您可以在需要时引入计数器,日志消息或JMX传感器。

交换或操作系统过载

使用JMX和DTrace,您可以分析操作系统的各个部分。使用REPL,您可以从正在运行的进程中获取操作系统和JVM统计信息。使用日志语句或自定义JMX传感器,您可以监控应用程序的性能指标。

在运行正常时测量应用程序的性能至关重要,因此您有一些基线值。否则,如果测量值很好或者表明存在问题,您将无法判断。