如何检测我的方法在等待什么?

2022-09-04 22:53:29

我在Java中有一个调用其他几个方法的方法。此方法是从固定线程池中的多个线程调用的。工作线程数与可用处理器(内核)数相同。

public void query() {
    method1();
    method2();
}

当我使用 VisualVM 分析程序执行时,时间和时间非常短,但自拍时间很长。但是除了两个调用之外,该方法没有其他代码。内部可能有同步 和 ,但在我能够控制的代码中没有明显的内容。method1()method2()query()method1()method2()

当我将池中的工人数量减少到1时,这种自我时间几乎消失了。整个程序的单线程和多线程执行时间几乎相同。我认为这意味着我的方法正在等待一些东西。query()

没有死锁,执行完成得很好。这两种方法调用了很多其他的东西,包括混淆jar中的库类,所以我不容易调试它。但是,该方法是直接从工作线程调用的,使用 。method1()method2()query()java.util.concurrent.ExecutorService


答案 1

在级别 3 对正在运行的进程发出 kill 命令。所有线程都将堆栈跟踪转储到标准 out,并且应用将继续运行。

kill -3 <pid>

请注意,您不会在发出 kill 命令的控制台上看到任何内容。Java 应用程序本身将具有输出。你可能需要检查日志,具体取决于应用重定向其输出的位置。


答案 2

我在一个代理类中发现了这个问题,该代理类将另一个类包装在自定义锁定机制中。

我继续创建一系列线程转储。由于我使用JVisualVM进行分析,因此在此过程中我创建了一些线程转储。 也工作了,就像Syneso在他的答案中提到的一样。Ctrl+Breakkill -3 <pid>

我使用注释中提到的线程转储分析器来分析它们。我不知道首先要寻找什么,但是由于TDA中对象和监视器的链接,我发现了这样的东西:

"pool-9-thread-32" #304 prio=5 os_prio=0 tid=0x000000002a706800 nid=0x348c waiting for monitor entry [0x000000003f06e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.example.MyClass.method1(MyClass.java:400)
    - waiting to lock <0x0000000680837b90> (a com.example.DifferentClass)
    at com.example.MyClass.query(MyClass.java:500)
    ... omitted ...
    at java.util.concurrent.FutureTask.run(FutureTask.java:270)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:618)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x000000075bc59aa8> (a java.util.concurrent.ThreadPoolExecutor$Worker)

DifferentClass扩展抽象,并且有一个从 到 的调用,其中 DTO 对象被传递给一个方法,该方法执行大量处理,日志记录并最终保存到数据库。代理类是在创建其中一个数据库处理类期间使用的。MyClassmethod1()DifferentClass