簡體   English   中英

分析多線程Java應用程序

[英]Analysing a multi-threaded Java application

在我參與的開源應用程序中,我們遇到了一個錯誤,應用程序並不總是正常關閉。 這就是我想要解決的問題。

經驗表明,這種情況大部分發生在線程和進程啟動時,但未正確管理(例如,線程正在等待套接字連接,應用程序正在關閉,線程一直在等待)。
考慮到這一點,我在整個源代碼中搜索了'.start()'並發現了53次(讓我感到有些害怕)。
作為第一步,我想創建一個幫助器類(ThreadExecutor),其中當前代碼'thread.start()'將被'ThreadExecutor.Execute(thread)'替換為a)現有源中只有一些更改和b)一個單獨的類,我可以很容易地檢查哪些線程沒有按預期結束。 要做到這一點,我想

  • 在調用Execute方法時,將要執行的線程添加到名為activeThreads的列表中
  • 啟動線程
  • 結束時將其從activeThreads列表中刪除。

這樣我就可以獲得所有正在執行的線程的最新列表,當應用程序掛起時,我可以看到哪個線程正在導致它。

問題:

  • 你對這個概念有什么看法? 我通常編寫c#並知道我是如何使用.NET與worker一起工作的,但我不太確定Java中最好的東西(我想在現有源代碼中修改盡可能少的代碼行)。
  • 如果概念似乎沒問題,我怎樣才能收到線程終止的通知。 我想避免額外的線程每隔一段時間檢查一次activeThreads中包含的所有線程的狀態,如果它們終止則刪除它們。

只是為了澄清:在弄清楚如何正確終止應用程序之前,我在這里要問的是找到哪些線程對於某些非常難以重現的測試用例的原因是什么是最好/最簡單的方法。

在更改任何代碼之前,我會嘗試分析您的應用程序的行為。 代碼更改可能會引入新問題 - 如果您嘗試解決問題,則不會出現您想要執行的操作。

關於當前運行的線程,內省應用程序狀態的最簡單方法是獲取線程轉儲。 你說你的問題是應用程序在關機時掛起。 這是應用線程轉儲的完美方案。 您將能夠看到哪些線程被阻止。

您可以在此處閱讀有關線程轉儲的更多信息。

嘗試創建所有線程守護進程(當所有剩余的線程都是守護進程時, JVM終止)。 在啟動每個線程之前使用thread.setDaemon(true)

你可以嘗試使用jvisualvm查看你的應用程序(它隨jdk一起提供,在你的jdk的bin文件夾中找到它)。 JVisualVM可以連接到您的應用程序並顯示許多有趣的信息,包括哪些進程仍在運行。 在開始你描述的道路之前,我會先試一試。

如果需要,這里有一些關於JVisualVM的文檔

java中最好的方法是直接使用線程池而不是線程(盡管直接使用線程)。 線程池接受Runnable對象,您可以將其視為“任務”。 這個想法是大多數線程會做一個小任務然后結束,因為制作一個Thread是昂貴的,並且管理器更難以使用線程池,這允許像'ThreadPoolExecutor.awaitTermination()`這樣的東西。 如果池中的任務數多於線程數,則剩余的任務將排隊。

Thread更改為Runnable非常簡單,您甚至可以在自己創建的線程上執行runnable。

請注意,這可能不適用於運行很長時間的線程,但您的問題似乎表明它們最終會完成。

至於你的第二個問題,找出某個線程在某一點運行的最好方法是在調試器(如Eclipse)中運行應用程序,並在close函數中暫停斷點上的所有線程。

我會嘗試jprofiler的試用版或類似的東西,它可以讓你深入了解你的應用程序及其線程實際做了什么。

不要更改代碼,但嘗試重現並了解何時發生這種情況。

創建一個靜態線程池。

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.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM