如何找出谁在Java中创建了一个线程?
想象一下:您在复杂的插件环境中使用~30 第三方 JAR。你启动它,运行大量代码,做一些计算,最后调用shutdown()。
这个生命周期通常可以正常工作,除了在每次运行中一些(非守护)线程保持悬空状态。如果每次关机都是最后一次关机,那就不会有问题,在这种情况下我可以简单地运行System.exit()。但是,这个循环可能会运行几次,并且每次传递都会产生更多的垃圾。
那么,我该怎么办?我在Eclipse的Debug View中看到了线程。我看到他们的堆栈痕迹,但他们没有任何关于它们的起源的暗示。没有创建者的堆栈跟踪,没有可区分的类名,没有。
有谁知道如何解决这个问题?
答案 0 :(得分:13)
好的,我能够自己解决(排序)这个问题:我把一个断点加入
Thread.start()
并手动逐步执行每次调用。通过这种方式,我很快发现 Class.forName()初始化了许多静态代码,这些代码反过来创建了这些神秘的线程。
虽然我能够解决我的问题,但我仍然认为更一般的任务仍未得到解决。
答案 1 :(得分:10)
我虔诚地命名我的线程(比如说使用Thread(Runnable, String)),否则他们最终会得到一个通用且有些无用的名字。转储线程将突出显示正在运行的内容以及(因此)创建它们的内容。这不能解决第三方线程的创建,我很感激。
编辑:JavaSpecialist时事通讯最近(2015年2月)通过使用安全管理器解决了这个问题。见here for more details更多:使用JavaSpecialist技术的一些细节:SecurityManager API包括在线程创建者的线程上调用的“checkAccess(newThreadBeingCreated)”。新线程已初始化其“名称”。因此,在该方法中,您可以访问线程创建者的线程和新线程,并且可以记录/打印等。当我尝试这个时,被监视的代码开始抛出访问保护异常;我通过在AccessController.doPriviledged(new PrivilegedAction(){...}下调用它来修复它,其中run()方法调用了被监视的代码。
答案 2 :(得分:1)
在调试Eclipse应用程序时,可以通过单击调试视图中的org.eclipse.equinox.launcher.Main字段来停止所有线程。
然后从那里,你可以看到每个线程的堆栈跟踪并进入thred run方法。
有时这可能会有所帮助,有时却不会。
正如Brian所说,命名线程是一个好习惯,因为这是轻松识别“谁创建它们”的唯一方法
答案 3 :(得分:0)
不幸的是,它没有。在Eclipse中,我看到了所有阻塞线程,但是它们的堆栈跟踪仅反映了它们的内部状态,并且(显然)没有公开有关其创建位置的信息。另外,从对象内部看(使用Variables视图),我无法获得任何进一步的提示。
答案 4 :(得分: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())
这将显示线程名称以及如何创建线程(堆栈跟踪),以便人们可以对其进行扫描。