【问题标题】:How to check which thread is holding the monitor?如何检查哪个线程正在持有监视器?
【发布时间】:2020-08-03 10:04:31
【问题描述】:

我遇到了性能问题(在使用并行集合和期货的复杂 Scala 代码中)。我使用 JFR 检查了更多细节,我可以看到问题表现为一个线程在等待监视器对象(该线程似乎正在通过调用 waitForkJoinTask 方法在 java.util.concurrent.ForkJoinTask#internalWait 中等待)。我想知道哪个线程持有这个监视器对象(以及从哪个函数/调用堆栈输入了监视器)。 JFR 向我显示了某种监视器地址,但我没有找到按此地址搜索/过滤的方法。

JMC 中是否有一些视图、插件或其他方式来检查谁以及何时锁定和释放给定的监视器?

【问题讨论】:

  • "jstack -l pid" 应该可以工作,不知道如何在 JFR 中做到这一点。
  • 监视器等待时间不够长,我无法手动触发 jstack(通常不到 1 秒)。我能够指示 JFR 每秒进行一次线程转储,这通常会达到所需的时间范围,但是我只能看到这些转储中的线程调用堆栈,而不是所采用的监视器列表。

标签: java multithreading scala jvm jfr


【解决方案1】:

问题是,正在等待的监视器对象在技术上不被任何线程持有。这样的监视器没有“所有者”。一般来说,你无法事先知道哪个线程负责调用notify,因为它可以是任何线程,也可以根本没有线程。

但是,如果已经通知了一个监视器,则会有一个 JFR 事件,其中包含有关 Notifier Thread 的信息。您可以在屏幕截图中看到:scala-execution-context-global-54 线程通知了监视器。

【讨论】:

  • 谢谢,有帮助。直到现在我才理解“通知程序线程”条目。尽管如此,鉴于我的大多数期货和并行循环都在同一个线程池上运行,不幸的是,这并不能告诉我太多,因为几乎任何代码都可以在该线程上运行。我想了解更多信息:我能以某种方式获取通知线程的事件的调用堆栈吗?这就是我的 OP 的目的——显示与给定监视器相关的事件应该告诉我我需要什么。如果这都不可能,你能想到其他办法吗?
  • @Suma 我在 JFR 中没有看到这个选项,但是您可以使用 async-profiler 记录带有堆栈跟踪的 notify 调用:运行 profiler.sh -e JVM_MonitorNotify ...
  • Async-profiler 也可以以 JFR 格式写入输出,因此可以同时运行 JFR 和 async-profiler,然后通过时间戳匹配它们的输出。
  • 感谢您的提示。我担心运行 async-profiler 对我来说很困难,因为我在 Windows 上运行。我将尝试一些虚拟机,但鉴于我的应用程序执行 3D 渲染,我不确定这将是多么容易。也许我可以在没有任何渲染的情况下提取一些复制品,这会让事情变得更容易。
猜你喜欢
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 2010-11-01
  • 2017-07-21
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多