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

Java 许多线程等待锁定一个对象,但没有线程持有该锁,java,multithreading,Java,Multithreading,我有一个应用程序,目前被卡住了,我试图了解为什么。 在kill-3(线程转储)输出中,我看到许多线程等待锁定一个对象(特别是等待向量的同步方法),但我没有看到任何线程持有该锁 你知道怎么调试吗 谢谢 另外,我知道Vector很旧,更推荐使用ArrayList,但这是我正在尝试调试的遗留代码。您描述的情况听起来像是死锁的典型案例 您可以(也许应该)使用诸如Eclipse或IntelliJ Idea之类的IDE,通过它您可以一步一步地调试您的应用程序,并准确地了解它在哪里停止以及做什么 或者,粘贴一

我有一个应用程序,目前被卡住了,我试图了解为什么。 在kill-3(线程转储)输出中,我看到许多线程等待锁定一个对象(特别是等待向量的同步方法),但我没有看到任何线程持有该锁

你知道怎么调试吗

谢谢


另外,我知道Vector很旧,更推荐使用ArrayList,但这是我正在尝试调试的遗留代码。

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

您可以(也许应该)使用诸如Eclipse或IntelliJ Idea之类的IDE,通过它您可以一步一步地调试您的应用程序,并准确地了解它在哪里停止以及做什么

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

可能的原因 以下问题通常会显示非常相似的症状(您的程序:

  • :共享资源上的循环依赖项
  • :已处理资源锁定,但未取得任何进展(前进一步,后退一步)
  • 当前位置做这项工作的人得不到他所需要的。其他人似乎都很忙,但没有取得任何进展
  • 重交换:进展如此缓慢,以至于系统停滞不前
  • 线程太多(操作系统过载):系统完全忙于管理资源,所以没有时间做真正的工作
诊断工具 开发人员计算机上的调试器 死锁和类似问题通常很难重现,因此无法用调试器轻松分析。该问题通常发生在实时系统上,但不会发生在开发人员机器上。原因可能是不同的工作负载、不同的数据组合,甚至是不同的操作系统或不同的硬件(更多的CPU内核等)

远程调试器 您可以尝试使用连接到生产系统。只有在生产机器可能完全停止(例如,由于HVM崩溃!)的情况下,您才应该这样做。您只应该在成对调试会话中这样做,并与对等方讨论每个步骤

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

答复 通过引入“命令行”()来查询实时系统。通过向实时系统添加命令行,您可以查询并更改部分命令行以诊断根本原因。您可以使用、或添加实时更改,并使用外部触发器来运行交换的代码(WebService、scheduler、message queue等)。成对工作(在运行之前讨论每个命令)并记住保护REPL不受外部访问(在本地主机或Unix套接字上绑定、使用命名管道、仔细检查防火墙、使用公钥授权、在特殊日志上记录每次访问等)

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

您可以通过提供或(更严格的输入,更好的兼容性)添加自己的传感器

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

活锁和资源匮乏 当您在worker中添加计数器时,当worker获得锁并且成功取得实际进展时,计数器将增加,很容易发现您的应用程序是否取得进展,或者哪些worker只是在处理资源而没有取得任何进展

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

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


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

Vector
ArrayList
有什么关系?只是解释一下为什么我们使用Vector(它的所有方法都是同步的),而不是通常更推荐的ArrayList。没有其他的reasonVector不只是旧的,它在1998年被ArrayList所取代。你知道多少人为什么在1998年之前写Java?如果你有一个非常旧的JVM,有一个bug,锁可能会a)进入坏状态或b)无法报告持有锁的线程。我会确保您的JVM尽可能最新,否则您可能会尝试调试多年前修复的错误。您可以发布线程转储和JVM详细信息吗?+1显而易见但非常正确。调试代码的最简单方法是使用调试器。通常线程转储是明确地