分析多线程Java应用程序

时间:2011-11-17 15:05:37

标签: java multithreading

在我参与的开源应用程序中,我们遇到了一个错误,应用程序并不总是正常关闭。这就是我想要解决的问题。

经验表明,这种情况大部分发生在线程和进程启动时,但未正确管理(例如,线程正在等待套接字连接,应用程序正在关闭并且线程一直在等待)。
考虑到这一点,我在整个源代码中搜索了“.start()”并发现了53次(让我有点害怕)。
作为第一步,我想创建一个帮助器类(ThreadExecutor),其中当前代码'thread.start()'将被'ThreadExecutor.Execute(thread)'替换为a)现有源中只有一些更改和b)一个单独的类,我可以很容易地检查哪些线程没有按预期结束。要做到这一点,我想

  • 在调用Execute方法
  • 时,将要执行的线程添加到名为activeThreads的列表中
  • 启动帖子
  • 结束时将其从activeThreads列表中删除。

这样我就拥有了所有正在执行的线程的最新列表,当应用程序在关机时挂起时,我可以看到哪些线程正在导致它。

问题:

  • 您对这个概念有何看法?我通常编写c#并知道我是如何使用.NET与worker一起工作的,但我不太确定Java中最好的东西(我想在现有源代码中修改尽可能少的代码行)。 / LI>
  • 如果概念似乎没问题,我怎样才能收到线程终止的通知。我想避免让一个额外的线程每隔一段时间检查一次activeThreads中包含的所有线程的状态,如果它们终止则删除它们。

只是为了澄清:在弄清楚如何正确终止应用程序之前,我在这里要问的是找到哪些线程对于某些非常难以重现的测试用例是最好/最简单的方法。

6 个答案:

答案 0 :(得分:6)

在更改任何代码之前,我会尝试分析您的应用程序的行为。代码更改可能会引入新问题 - 而不是您在尝试解决问题时想要做的事情。

关于当前运行的线程,内省应用程序状态的最简单方法是获取线程转储。你说你的问题是应用程序在关机时挂起。这是应用线程转储的完美方案。您将能够看到哪些线程被阻止。

您可以阅读有关线程转储here的更多信息。

答案 1 :(得分:2)

尝试创建所有线程守护进程(当所有剩余线程都是守护进程JVM终止时)。在开始每个帖子之前使用thread.setDaemon(true)

答案 2 :(得分:2)

您可以尝试使用jvisualvm(jdk附带的,在jdk的bin文件夹中找到它)查看您的应用程序。 JVisualVM可以连接到您的应用程序并显示许多有趣的信息,包括哪些进程仍在运行。在开始你描述的道路之前,我会先试一试。

如果需要,可以在JVisualVM上使用documentation

答案 3 :(得分:2)

java中最好的方法是直接使用Thread pools而不是Threads(尽管直接使用线程)。线程池接受Runnable个对象,您可以将其视为“任务”。这个想法是大多数线程会做一个小任务然后结束,因为使Thread成本高昂且经理难以管理你可以使用线程池,它允许像'ThreadPoolExecutor.awaitTermination()`这样的东西。如果您在池中拥有的任务多于线程,则其余任务将排队等候。

Thread更改为Runnable很简单,您甚至可以在自己创建的线程上执行runnable。

请注意,这可能不适用于运行很长时间的线程,但您的问题似乎表明它们最终会完成。

至于你的第二个问题,找出某个线程在某个点上运行的最好方法是在调试器(如Eclipse)中运行应用程序,并在close函数中暂停断点上的所有线程。

答案 4 :(得分:1)

我会尝试jprofiler的试用版或类似的东西,它可以让你深入了解你的应用程序及其线程实际上做了什么。

不要更改代码,但尝试重现并了解何时发生这种情况。

答案 5 :(得分:1)

创建一个静态线程池。

static ExecutorService threads = Executors.newCachedThreadPool();

每次线程更改的开始:

new Thread(new AThread()).start();

threads.submit(new AThread ());

当你的代码退出时,列出所有正在运行的线程:

List<Runnable> runningThreads = threads.shutdownNow();
for ( Runnable t : runningThreads ) {
  System.out.println("Thread running at shutdown: "+t.toString());
}

这不仅会关闭所有正在运行的线程,还会列出它们以便查看它们的问题。

编辑:已添加

如果要跟踪所有正在运行的线程,请使用:

Future f = threads.submit(new AThread ());

并将其存储在某个列表中。然后,您可以通过以下呼叫了解其状态:

f.isDone();
... etc.