简体   繁体   English

分析多线程Java应用程序

[英]Analysing a multi-threaded Java application

In an open source application I'm participating, we've got a bug, where the application doesn't always close properly. 在我参与的开源应用程序中,我们遇到了一个错误,应用程序并不总是正常关闭。 That's what I'd like to solve. 这就是我想要解决的问题。

Experience has shown that this happens most of the time when threads and processes are being started, but not managed correctly (eg a thread is waiting on a socket connection, the application is being shut down and the thread keeps on waiting). 经验表明,这种情况大部分发生在线程和进程启动时,但未正确管理(例如,线程正在等待套接字连接,应用程序正在关闭,线程一直在等待)。
With this in mind I've searched for '.start()' in the entire source and found 53 occurrences (which scared me a bit). 考虑到这一点,我在整个源代码中搜索了'.start()'并发现了53次(让我感到有些害怕)。
As a first step, I wanted to create a helper class (ThreadExecutor) where the current code 'thread.start()' would be replaced by 'ThreadExecutor.Execute(thread)' to have a) only a few changes in the existing source and b) a single class where I can easily check which threads don't end as they should. 作为第一步,我想创建一个帮助器类(ThreadExecutor),其中当前代码'thread.start()'将被'ThreadExecutor.Execute(thread)'替换为a)现有源中只有一些更改和b)一个单独的类,我可以很容易地检查哪些线程没有按预期结束。 To do this I wanted to 要做到这一点,我想

  • add the thread to be executed to a list called activeThreads when calling the Execute method 在调用Execute方法时,将要执行的线程添加到名为activeThreads的列表中
  • start the thread 启动线程
  • remove it from the activeThreads list when it ends. 结束时将其从activeThreads列表中删除。

This way I'd have an up to date list of all executing threads and when the app hangs on shutdown I could see in there which thread(s) is(are) causing it. 这样我就可以获得所有正在执行的线程的最新列表,当应用程序挂起时,我可以看到哪个线程正在导致它。

Questions: 问题:

  • What do you think about the concept? 你对这个概念有什么看法? I'm usually coding c# and know how I'd do it using .NET with workers, but am not too sure what's best in Java (I'd like to modify as few lines of code as possible in the existing source). 我通常编写c#并知道我是如何使用.NET与worker一起工作的,但我不太确定Java中最好的东西(我想在现有源代码中修改尽可能少的代码行)。
  • If the concept seems ok, how can I get notified of a thread terminating. 如果概念似乎没问题,我怎样才能收到线程终止的通知。 I'd like to avoid having an additional thread checking every once in a while what the state of all threads contained in activeThreads is, to remove them if they terminated. 我想避免额外的线程每隔一段时间检查一次activeThreads中包含的所有线程的状态,如果它们终止则删除它们。

Just to clarify: Before figuring out how to terminate the application properly, what I'm asking here is what's the best/easiest way to find which threads are at cause for certain test cases which are pretty hard to reproduce. 只是为了澄清:在弄清楚如何正确终止应用程序之前,我在这里要问的是找到哪些线程对于某些非常难以重现的测试用例的原因是什么是最好/最简单的方法。

I would attempt to analyze your application's behavior before changing any code. 在更改任何代码之前,我会尝试分析您的应用程序的行为。 Code changes can introduce new problems - not what you want to do if you're trying to solve problems. 代码更改可能会引入新问题 - 如果您尝试解决问题,则不会出现您想要执行的操作。

The easiest way to introspect the state of your application with regard to which threads are currently running is to obtain a thread dump. 关于当前运行的线程,内省应用程序状态的最简单方法是获取线程转储。 You said that your problem is that the application hangs on shutdown. 你说你的问题是应用程序在关机时挂起。 This is the perfect scenario to apply a thread dump. 这是应用线程转储的完美方案。 You'll be able to see which threads are blocked. 您将能够看到哪些线程被阻止。

You can read more about thread dumps here . 您可以在此处阅读有关线程转储的更多信息。

Try to make all threads daemon(when all remaining threads are daemon the JVM terminates). 尝试创建所有线程守护进程(当所有剩余的线程都是守护进程时, JVM终止)。 Use thread.setDaemon(true) before starting each thread. 在启动每个线程之前使用thread.setDaemon(true)

You could try to look into your application using jvisualvm (which is shipped with the jdk, find it in the bin folder of your jdk). 你可以尝试使用jvisualvm查看你的应用程序(它随jdk一起提供,在你的jdk的bin文件夹中找到它)。 JVisualVM can connect to your application and display a lot of interesting information, including which processes are still running. JVisualVM可以连接到您的应用程序并显示许多有趣的信息,包括哪些进程仍在运行。 I'd give that a shot before starting down the road you describe. 在开始你描述的道路之前,我会先试一试。

Here is some documentation on JVisualVM should you need it. 如果需要,这里有一些关于JVisualVM的文档

The best way in java is to use Thread pools instead of Threads directly (although using threads directly is accepted). java中最好的方法是直接使用线程池而不是线程(尽管直接使用线程)。 Thread pools accept Runnable objects, which you can see as Tasks. 线程池接受Runnable对象,您可以将其视为“任务”。 The idea is that most threads would do a small task and then end, because making a Thread is expensive and harder to manager you can use the threadpool, which allows things like 'ThreadPoolExecutor.awaitTermination()`. 这个想法是大多数线程会做一个小任务然后结束,因为制作一个Thread是昂贵的,并且管理器更难以使用线程池,这允许像'ThreadPoolExecutor.awaitTermination()`这样的东西。 If you have more tasks than Threads in the pool, remaining tasks will just be queued. 如果池中的任务数多于线程数,则剩余的任务将排队。

Changing a Thread into a Runnable is easy, and you can even execute a runnable on a Thread you make yourself. Thread更改为Runnable非常简单,您甚至可以在自己创建的线程上执行runnable。

Note that this might not work for threads that run a long time, but your question seems to suggest that they will eventually finish. 请注意,这可能不适用于运行很长时间的线程,但您的问题似乎表明它们最终会完成。

As for your second question, the best way to find out which threads are running at a certain point is to run the application in a debugger (such as Eclipse) and pause all threads on a breakpoint in the close function. 至于你的第二个问题,找出某个线程在某一点运行的最好方法是在调试器(如Eclipse)中运行应用程序,并在close函数中暂停断点上的所有线程。

I would try the trial edition of jprofiler or something similar, which gives you a lot of insight into what your application and its threads actually do. 我会尝试jprofiler的试用版或类似的东西,它可以让你深入了解你的应用程序及其线程实际做了什么。

Don't change the code yet, but try to reproduce and understand when this happens. 不要更改代码,但尝试重现并了解何时发生这种情况。

Create yourself a static thread pool. 创建一个静态线程池。

static ExecutorService threads = Executors.newCachedThreadPool();

For every start of thread change: 对于每次线程更改的开始:

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

to

threads.submit(new AThread ());

When your code exits, list all running threads with: 当您的代码退出时,列出所有正在运行的线程:

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

This will not only shut down all running threads, it will list them out for you to see what their issue is. 这不仅会关闭所有正在运行的线程,还会列出它们以便查看它们的问题。

EDIT : Added 编辑 :添加

If you want to keep track of all running threads use: 如果要跟踪所有正在运行的线程,请使用:

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

and store it in a list somewhere. 并将其存储在某个列表中。 You can then find out about its state with calls like: 然后,您可以通过以下呼叫了解其状态:

f.isDone();
... etc.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM