2016-12-26 52 views
3

摘要如何維護一個持久的後臺線程?

我有,應該是長時間運行的服務器,並且滋生了IO幾個後臺線程。我試圖確保後臺/ IO線程不會停止,或者如果它們停止運行,它們將被恢復。

目前的解決方案

目前我主循環只檢查所有的背景調查(以下僞代碼)的狀態。我認爲應該有更好的辦法。

while (!Thread.currentThread().isInterrupted()) { 
    maintainThreads(); 
    doWork(); 
    condition.await(30, TimeUnit.SECONDS); 
} 

我嘗試

我考慮切換到SingleThreadExecutor,具有自定義queue時,它拉的下一個任務將不會刪除Runnableexecutor然後會管理我的線程,所以我可以把它從我的主循環。

我擔心每個線程有一個執行程序會帶來性能問題,並且存在針對此問題的更簡單/更好的解決方案。我也考慮過爲每個線程設置關閉鉤子,讓它們自己重新啓動。

任何幫助,將不勝感激。

+0

「go down」是什麼意思?你的意思是說,一些包含代碼引發異常?你可以在try/catch中包裝你的'run()'方法的主體,這樣可以防止線程終止異常 - 但是你必須考慮很長時間並且很難了解你的'doWork()'和其他方法來拋出異常。是否有可能繼續? – BeeOnRope

+0

[UncaughtExceptionHandler](http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.UncaughtExceptionHandler.html?is-external=true)? – GPI

+0

@BeeOnRope我維護的線程大多隻是IO連接('doWork()'的生成器),它已經捕獲了所有檢查的異常。如果線程要終止,那麼主循環只是在旋轉,所要做的就是記錄問題並嘗試重新創建它們直到它們連接。我想我的主要問題是「假設我想要一個線程運行,只要我的程序正在運行,無論是什麼導致它停止運行,乾淨的方法是什麼」。 – billie

回答

1

這裏真正的疑難雜症是你的意思是通過進去下來「或者他們會被帶到備份,如果他們下去。」

只有兩種方法,我知道的線程可以下去無需將整個過程本身在java中退出:

  1. run()方法終止,或者通過異常或整理的run方法通常是(即非例外)。
  2. Thread.stop()在您的線程上被調用。

我們首先解決(2) - Thread.stop()已被棄用,並且在任何行爲良好的應用程序中都是一個很大的禁忌。你幾乎可以認爲它不會被調用,因爲如果它被調用,你的application is already badly broken。由於您的應用程序處於不一致狀態,此時重新啓動任何線程可能會產生未定義的效果。

那麼對於(1),您只需確保run()不會終止。它不會終止正常因爲你已經設置了一個無限循環。要阻止它異常終止,您可以catch (Throwable t)並保持循環(在正確記錄錯誤之後)。

當然,沒有後續重新拋出的catch (Throwable t)通常是一種代碼異味。這意味着你抓住了一些未明確的錯誤,然後決定繼續前進。錯誤的範圍可以從良性(例如,因爲遠程客戶端斷開而導致的SockedClosedExcpetion)到不可恢復的(例如,OutOfMemoryError或更糟)。你應該真的問自己,如果你想要這個線程繼續面對任何類型的異常。

您的應用程序可能是無效狀態,可能無法繼續。一種妥協方法是僅捕獲Exception的子類並終止Error上的應用程序。更保守的方法是在任何你不知道如何處理的異常類型(並將其視爲需要修復的錯誤)上終止應用程序。

1

維護持久後臺線程的一個重要部分是在線程級別正確處理您的異常。在處理錯誤條件時,尤其是在頂級服務器/守護程序代碼中的異常情況下,您需要牢記一些例外無法處理!遇到這種例外情況時,應立即退出或嘗試儘可能清潔,然後退出。

例如,不應處理大多數類型爲Error的異常。這包括java.lang.VirtualMachineError異常:InternalError,OutOfMemoryError,StackOverflowError,UnknownError等。正如前面的回答所述,捕獲Throwable是一個很大的No-No,因爲很多異常無法恢復。想想你的失敗策略 - 何時失敗是有道理的,在這種情況下你可以做什麼(可能會記錄錯誤或向用戶顯示消息)。

嘗試始終正確處理InterruptedException,因爲它可以讓您有時間清理並正常關閉線程。否則你冒着數據損壞的風險。

有關更多異常處理提示,請檢查我的Exceptions Guidelines帖子。

0

對於應用程序,進程(不是線程)重新創建/重新啓動是最可靠的故障恢復方法。

真正的關鍵任務系統如何處理失敗?通過提供冗餘,心跳監測,快速切換等。

不要試圖盲目保留已失敗的線程。有很多原因可能會破壞我們的過程,我們(人類)只知道其中的幾個原因。

如果我們FAIL FAST並重啓進程,OS內核確保我們清理初始狀態。所以即使我們的程序不太可靠,程序也會運行並在一段時間內完成這項工作。