2012-02-02 94 views
2

我創建了一個多線程應用程序,它使用相同的ScheduledExecutorService(方法scheduleAtFixedRate和一個固定的10個線程的線程池)執行不同的任務。然而,除了一個主要任務之外的所有線程(不要與主線程混淆!)大部分時間都在睡覺,直到有用戶輸入。主任務和其他(用戶輸入)線程之間共享的數據受同步塊中的鎖對象保護。Java ScheduledExecutorService - 需要關於實時性能問題的建議

主要任務以相當大的頻率執行重複任務,例如25赫茲(即40毫秒的週期),重要的是及時執行此任務。通常情況也是如此,但不幸的是並非全部。其他「很好」的應用程序也運行在同一臺計算機上(Linux OP),但是CPU 100%運行在100%以上。在60分鐘的測量期間(即90000個樣品),在約50個樣品中,兩個連續樣品之間的實際週期>≥60ms,並且其中約30個週期超過100ms,在幾個非常差的病例(時間相當接近,以秒爲單位),時間在1000到2300毫秒之間。在測量過程中沒有用戶輸入。看看數據日誌,看起來很明顯,有些東西阻止執行程序在這些時間間隔內執行其工作,因爲它們通常跟着執行程序的「追趕」,即在2或3毫秒內從應用程序中獲取多個日誌。

我已經嘗試過在每次執行任務時定期進行垃圾回收,但是(至少從短期來看)它似乎只會讓事情變得更糟。我也測量了任務的執行時間。它大部分是大約1毫秒,它不應該導致執行器崩潰(或者應該這樣做?)。在這裏也有的偏差,偶爾也會在100ms左右,但他們可以解釋不到50%的延遲。我試過尋找TaskRejectedExceptions,什麼都沒發現。

所以我現在的問題基本上是:我可以期待從一個ScheduledExecutorService隨着時間的推移?這可能是一個線程問題,儘管在這些情況下只有主要任務應該運行嗎?什麼可能會導致ScheduledExecutor暫時停止執行,只能用它的「追趕」數據來洪泛日誌,並且是否有任何方法來控制這種惱人的行爲?這可能與我的JVM僅僅是沒有實時優先級功能的普通JVM有關嗎?任何關於從哪裏開始挖掘的幫助,想法或理論,都會得到真正的讚賞!

+0

我相信你沒有通過任務的記錄時間來判斷任務的執行時間,而是明確地測量並打印出調用之間的時間? – Perception 2012-02-02 22:35:32

+0

這有點令人困惑。所以你所說的測量是兩次執行主任務的動作之間的時間,應該每40ms執行一次。 – Tudor 2012-02-02 22:36:19

+0

很難說,但日誌和垃圾回收可以大量影響'及時'的性能。要專注於日誌記錄,您可能不應該在執行程序的某個線程中運行任何日誌記錄代碼。控制GC出現並不在我的聯盟中,並且高度依賴於您正在使用的JVM。最好的一般技巧是儘量減少對象的創建,但當GC中斷你的應用程序時(除非你精確地定製你的應用程序和JVM設置),*會*得到一個點。 – 2012-02-02 22:39:37

回答

0

根據計時器documentation,你的情況似乎完全正常:

在固定速率執行,每個執行相對於初始執行的安排執行時間安排。如果由於任何原因(例如垃圾收集或其他後臺活動)延遲執行,兩個或更多執行將會快速連續發生以「趕上」。從長遠來看,執行的頻率恰好是指定週期的倒數(假設系統時鐘基礎Object.wait(long)是準確的)。

事實是,scheduleAtFixedRate()不能保證執行將在它應該開始的時候準確地開始,而只是在長期運行中的頻率。 其實,我不確定是否有辦法來完成使用Java。

+0

實際上沒有辦法在大多數情況下實現你需要一個實時的操作系統,即使在linux下的實時調度程序下運行一個C程序,我們發現它不能保證一個固定的速率(儘管我們測量的速度遠遠小於並且幾乎沒有java中的OP測量器) – nos 2012-02-02 23:36:43

0

的幾個注意事項:

  • 調用垃圾回收器並不保證收集很可能會思考的方式。從Java文檔:

調用該方法表明Java虛擬機 努力朝着回收未使用的對象,以使他們當前佔用快速重用內存 。

這裏的關鍵是建議。永遠不要期望它完全按照您的預期運行。你也不能期望它能夠阻止實際的系統垃圾收集在另一次運行。

  • 線程已安排,但仍然可以按計劃實際執行它們。您的處理器使用率不足100%並不意味着它必須能夠執行另一個線程。一般來說,期望在沒有從頭開始完全編寫的環境中高度準確地實時執行線程可能不會導致期望的結果。