【问题标题】:Many threads waiting to lock an object, but no thread is holding that lock许多线程等待锁定一个对象,但没有线程持有该锁
【发布时间】:2014-02-12 08:51:06
【问题描述】:

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

知道如何调试吗?

谢谢

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

【问题讨论】:

  • VectorArrayList 与这个问题有什么关系?
  • 只是解释为什么我们使用Vector(它的所有方法都是同步的),而不是通常更推荐的ArrayList。没有其他原因
  • Vector 不只是老了,它在 1998 年被 ArrayList 取代。你知道有多少人为什么在 1998 年之前写 Java?
  • 如果你有一个非常旧的 JVM,有一个错误,锁可能 a) 进入错误状态或 b) 无法报告持有锁的线程。我会确保您的 JVM 尽可能保持最新状态,否则您可能会尝试调试多年前修复的错误。
  • 你能发布线程转储和 jvm 的详细信息吗?

标签: java multithreading


【解决方案1】:

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

您可以(或许应该)使用 Eclipse 或 IntelliJ Idea 等 IDE,通过它您可以逐步调试您的应用程序并准确了解它在哪里停止以及要做什么。

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

【讨论】:

  • +1 明显但非常真实。调试代码最简单的方法是使用调试器。
  • 如果出现死锁,通常线程转储会显式写入...我不能真正使用 IDE,因为我无法再次重现它,或者至少我不知道如何现在重现它。
  • 如果无法重现问题,那么问题可能是由于环境中的资源(例如 CPU、内存等)有限,而不是代码中的逻辑。
【解决方案2】:

可能的原因

以下问题通常会表现出非常相似的症状(您的程序:

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

诊断工具

开发者机器上的调试器

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

远程调试器

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

记录和可视化

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

REPL

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

JMX

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

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

诊断

死锁

JConsole 和 VisualVM 都具有查找死锁并显示死锁所涉及的线程的功能。结合显示每个线程的当前堆栈跟踪的功能,诊断死锁变得轻而易举。

活锁和资源匮乏

当您在工作人员中添加计数器时,当工作人员获得锁并且工作人员已成功取得实际进展时,计数器会增加,很容易发现您的应用程序是否取得进展,或者哪些工作人员只是在处理周围的资源而没有实现任何目标。

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

交换或操作系统过载

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

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

【讨论】:

  • 你的大部分答案不是关于没有线程持有锁的问题!
猜你喜欢
  • 2014-12-22
  • 2018-11-30
  • 1970-01-01
  • 2022-01-03
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 2015-05-24
相关资源
最近更新 更多