22

如何找出谁在 Java 中创建了线程?

想象一下:您在一个复杂的插件环境中使用了大约 30个第三方JAR。你启动它,运行大量代码,进行一些计算,最后调用shutdown()。

这个生命周期通常工作得很好,除了在每次运行时一些(非守护进程)线程仍然悬空。如果每次关机都是最后一次关机,这不会有问题,在这种情况下我可以简单地运行 System.exit() 。但是,这个循环可能会运行多次,并且每次通过都会产生更多的垃圾。

所以我该怎么做?我在 Eclipse 的调试视图中看到了线程。我看到了他们的堆栈跟踪,但他们不包含任何关于其来源的提示。没有创建者的堆栈跟踪,没有可区分的类名,什么都没有。

有谁知道如何解决这个问题?

4

5 回答 5

14

好的,我能够自己解决(某种)问题:我在其中设置了一个断点

Thread.start() 

并手动逐步执行每个调用。这样我很快就发现Class.forName()初始化了很多静态代码,这些代码反过来又创建了这些神秘的线程。

虽然我能够解决我的问题,但我仍然认为更一般的任务仍未解决。

于 2009-08-04T13:34:11.387 回答
10

我虔诚地命名我的线程(例如使用Thread(Runnable, String)),否则它们最终会得到一个通用且有点无用的名称。转储线程将突出显示正在运行的内容以及(因此)创建它们的内容。这并不能解决第 3 方线程的创建,我很感激。

编辑:JavaSpecialist 通讯最近(2015 年 2 月)通过使用安全管理器解决了这个问题。请参阅此处了解更多详细信息

更多:使用 JavaSpecialist 技术的一些细节:SecurityManager API 包括在线程创建者的线程上调用的“checkAccess(newThreadBeingCreated)”。新线程已经初始化了它的“名称”。因此,在该方法中,您可以访问线程创建者的线程和新线程,并且可以记录/打印等。当我尝试这样做时,被监控的代码开始抛出访问保护异常;我通过在 AccessController.doPriviledged(new PrivilegedAction() { ... } 下调用它来解决这个问题,其中 run() 方法调用了被监视的代码。

于 2009-08-04T12:42:53.010 回答
1

在调试 Eclipse 应用程序时,您可以通过单击调试视图中的 org.eclipse.equinox.launcher.Main 字段来停止所有线程。

然后从那里,对于每个线程,您可以看到堆栈跟踪并上升到 thred run 方法。

有时这会有所帮助,有时则无济于事。

正如布赖恩所说,命名线程是一种很好的做法,因为这是轻松识别“谁创建它们”的唯一方法

于 2009-08-04T12:57:12.827 回答
0

不幸的是,它没有。在 Eclipse 中,我看到了所有阻塞线程,但它们的堆栈跟踪只反映了它们的内部状态,并且(显然)没有透露有关它们创建位置的信息。同样从对象内部看(使用变量视图),我无法引出任何进一步的提示。

于 2009-08-04T12:50:00.663 回答
0

出于本地调试目的,可以尽早将调试器附加到 Java 应用程序。

在结束时设置一个非暂停断点java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean)评估并记录以下内容:

"**" + getName() + "**\n" + Arrays.toString(Thread.currentThread().getStackTrace())

这将输出线程名称以及线程是如何创建的(堆栈跟踪),人们可以通过它进行扫描。

于 2019-12-26T08:06:48.127 回答