2017-08-08 67 views
1

我有一個在Ubuntu 16.04 LTS上運行的Java應用程序。關閉線程在執行端點呼叫時消失

當應用程序接收到關閉信號,停止序列像這樣運行:

Runtime.getRuntime().addShutdownHook(new Thread() { 
     @Override 
     public void run() { 
      shutdown(); 
     } 
    }); 

這工作得很好,但只要我嘗試調用外部REST端點(我用的改造,其中Rx Observable)線程完全消失,端點永遠不會被調用,並且連續的命令不再被執行。

  • 我首先想到Observables會是問題,並使用改造Call來代替。同樣的問題。
  • 然後我嘗試進行同步調用,而不是調用端點異步。同樣的問題。
  • 關機時間不是問題。我明確地給了30秒。

我認爲這與線程有關,當一個庫在關閉時創建額外的線程時,JVM似乎會殺死所有內容。

任何人都可以擺脫光線或建議我可以嘗試什麼,請。

-

額外信息:

我需要執行長期運行的清理。問題是我無法確定關閉信號是如何看起來像什麼時候發生的,因爲JVM運行在一個Docker容器中,該容器在docker stop(當主機停止時)首先發送SIGTERM,然後在超時之後(我可以設置,目前60秒)SIGKILL。容器中的JVM運行socket.io,可以連接數千個客戶端。我希望使用60秒向每個客戶端發送good-bye,並乾淨地斷開這些連接,並從負載均衡器註銷服務器。所以在清理過程中有很多潛在的阻塞操作。

如果你的Java認爲,清理總是短暫的,那麼Java是錯誤的:(

+2

關閉掛鉤應儘快退出,並且肯定不參與網絡操作。看到Javadoc。 – EJP

回答

2

當因此,一旦關閉JVM你的情況提出了中斷的標誌。當你調用任何阻塞操作,一個馬上會如果你必須在你的應用程序終止時執行進一步的,可能持久的代碼,那麼關閉鉤子不是一個好辦法,它可以關閉開放的資源,而不是創建新的。

由於您沒有提供關於您的代碼的進一步信息,我不能給出一個確切的建議,但總體思路是讓主線程在應用程序運行時等待,並讓那個人執行清理工作。在這種情況下,您需要關閉信號而不是系統關閉信號,因此應用程序可以繼續正常運行。

如果是出於某種原因太複雜,你可以嘗試做這樣的事情,以清除在您關閉掛鉤的開始中斷的標誌:

try { 
    Thread.sleep(1); 
} catch (InterruptedException e) { 
} 

然而,這是違反規定的,以及那些存在因爲某種原因。即操作系統可能會認爲你的程序掛起,如果它不能對kill信號作出足夠快的反應,並以更糟糕的方式終止它。

+0

這回答我的問題。如果您有更多的想法,我仍然在上面添加額外的信息。但是我猜中斷線程是我能做的唯一事情,並且它相當安全,因爲「OS是Docker」,如果我的中斷線程沒有按時退出,它將發送'SIGKILL'。 –