2011-07-25 59 views
2

我有一個Swing應用程序,它使用addShutdownHook()處理Ctrl + C,它可以正常工作,直到我有一個關閉任務調用一個正常情況下更改JLabel文本的關閉任務指出它掛起。檢測到JVM正在關閉

我認爲問題在於Swing EDT已終止或正在等待某事。

有沒有方法可以確定EDT已經終止或「已完成」(這樣我可以避免調用Swing方法),或防止Ctrl-C上通常關閉所有窗口的行爲?


只是爲了澄清:

我有一個名爲stop()類中的方法。在正常情況下,可以調用這個函數(連同其補充start()),並觸發導致JLabel更新的事件級聯,以獲得發生stop()的視覺反饋。

當我的關機掛鉤運行時,我需要撥打stop()正常關閉一些資源。

我在問的是如何檢測到Swing EDT不存在,因此我可以重寫stop(),以便它檢測到Swing的缺失並避免調用Swing函數。

回答

0

我結束了在關閉掛鉤的開頭設置一個標誌,和通信這(通過提前設置的時間對象)與對象我stop()方法,以便它可以測試這個標誌,並決定是否要調用Swing方法。

如果關機標誌沒有設置,Swing的方法被調用。否則,他們不」噸。

+0

這將在一些時間工作。但是,它仍然取決於事件關閉的順序。由於您無法控制線程按什麼順序關閉,也無法按照什麼順序啓動關閉鉤子,導致鎖定的事件順序仍可能發生:(1)由於Ctrl + C,JVM開始關閉;(2) Swing線程被關閉,並且你的關閉鉤子還沒有被調用,(3)調用導致JLabel請求被改變的調用被稱爲 - 你的應用程序掛起(4)你的關閉鉤子被調用 - 但是爲時已晚防止無效/鎖定呼叫。 – jefflunt

+0

@normalocity:不擔心,至少在這個問題的背景下。如果我發現序列(2),(3)如您所描述的那樣發生,那麼我需要處理一個單獨的問題,即使我沒有使用任何關閉掛鉤,也會發生這種情況。 –

+0

好吧,無論哪種方式,我很高興你的代碼工作。畢竟,你是自己的代碼的工程師,所以如果你不擔心它,那麼我不能擔心它。提醒我你的其他問題:http://stackoverflow.com/questions/508850/java-concurrency-cynicism-gone-too-far我真的很喜歡併發代碼,所以我只是解決這些多線程問題的粉絲, 是全部。 – jefflunt

2

關閉掛鉤不應期望其他服務處於已知狀態(例如UI事件處理線程等),因爲應用程序已被請求關閉。編寫一個試圖更新鉤子控制內不是100%的東西的關閉鉤子可能會導致這種情況和其他行爲,這將很難排除故障。

addShutdownHook方法特別提到這種情況,並警告您不應該嘗試這些類型的操作,因爲這樣做很容易導致意想不到的後果,例如您觀察到的鎖定。

the documentation

關機鉤在在虛擬機 的生命週期微妙時間運行,因此應防守編碼。他們應該在 特別是寫成線程安全的,並儘可能避免死鎖 。他們也不應該盲目地依賴服務 ,這些服務可能已經註冊了自己的關閉掛鉤,因此可能在關閉過程中自己註冊。

在這種情況下,由於Swing是一個您不能控制的多線程UI系統,我建議您不要在程序生命的關閉階段嘗試更改UI中的任何內容。這樣做會導致奇怪的,不可預知的,有時不可重複的情況,這些情況可能因運行而異,或從一臺機器到下一臺機器,這取決於線程如何計劃關機。另一個線程如何以及何時停止其工作並非旨在以線性,可預測的方式發生。因此,在多線程程序中編寫的任何代碼都依賴於另一個線程在特定時間處於特定狀態(除非那些線程明確地相互通信了他們的狀態),這些代碼將爲您打開這些類型的的問題。

我想我的後續問題是,「爲什麼你想/需要在關機過程中更改JLabel?「如果你想在關閉之前改變某些東西的狀態,那麼可以將鍵盤輸入作爲常規事件捕捉(防止導致應用程序關閉),更改JLabel文本,然後啓動通過調用該應用自己的關機System.runFinalization()和/或System.ext(int)

+0

對,這就是爲什麼我問'有沒有辦法確定EDT已經終止或「完成」,所以我可以避免調用Swing函數。 –

+0

不是真的,沒有。總而言之,在關機過程中,你不能依賴另一個線程的狀態 - 所以試圖這樣做總是會讓你走上困難的道路。我已經用另一段更​​新了我的答案,提供了一個替代方案。 – jefflunt

+0

謝謝。我不想改變JLabel--我正在調用一個我在正常情況下使用的函數。 –

2

下面的技巧有助於確定JVM是否處於關閉周圍沒有經過任何標誌的過程:

private static final Thread DUMMY_HOOK = new Thread(); 

public static boolean isShuttingDown() 
{ 
    try { 
     Runtime.getRuntime().addShutdownHook(DUMMY_HOOK); 
     Runtime.getRuntime().removeShutdownHook(DUMMY_HOOK); 
    } catch (IllegalStateException e) { 
     return true; 
    } 

    return false; 
} 

但是不要忘了可能併發問題。