2013-07-31 44 views
0

我去討論基本查詢我想首先聲明,我完全清楚我的問題是對AWT/Swing的框架標準之前的必要性。我的查詢僅僅是作爲一種學術經驗,並且應該(希望)不會應用於真實世界的應用程序。調度簡單事件與EDT

的AWT/Swing的框架在使用單個線程分派事件基於事件的模型構建。所有AWT/Swing的相關事件的事件必須在事件調度線程(EDT)和程序員已經編程必須通過功能invokeAndWait()和invokeLater的()進行排隊,任何自定義事件處理。雖然這種模式保證了框架從來沒有從任何類型的線程併發的問題受到它提供了很大的痛苦於程序員試圖寫它周圍的代碼(在計算器搜索擺動問題......很少數)。

但是......多年前,在我更熟悉AWT/Swing模型和EDT之前,我曾經寫過違反許多Java標準的代碼(代碼會讓任何合理的編程人員驚恐地反彈)。我違反了這些標準之一就是調用通過非EDT的線程更新GUI的方法。準確地說,這是一個標準的「長期」任務,它駐留在一個輔助線程上,該輔助線程用當前進度定期更新JLabel。現在回顧一下代碼,我意識到儘管代碼直接違反了標準,但它在100%的時間內都能正常工作。我注意到沒有閃爍,沒有文本損壞(因爲它是JLabel),沒有隨機的異常被拋出,也沒有異常的GUI行爲。當然,我從一個小例子知道,不能簡單地確定AWT/Swing標準是過度保護或不必要的。而與此,我查詢在於:

對於喜歡(甚至不以恆定的速率,也許一次或兩次第二)更新的JLabel簡單的任務是確有必要通過EDT執行呢?什麼是可能的影響(除了被整個Java編程社區所鄙視)(我想要一個可靠的含義列表,而不僅僅是「它可能導致EDT陷入困境」)?

假設只有一個線程更新GUI(不是EDT)並且更新不頻繁並且僅在原子操作(更新字符串,原始數據等)中更新的模型纔有可能使程序可以自由運行由EDT引起的問題(我猜這算作是一種黑客?)。

作爲一個挑戰,我想知道是否有人可以拿出代碼來演示違反AWT/Swing模型的代碼,通過從另一個線程調度事件引起顯而易見的和不變的(如我不必等待2小時讓GUI閃爍1幀)問題?

順便說一句,這可能是不相關的,但是新的EDT線程產生新的JFrame/Window對象還是所有的線程運行在同一個線程?我無法想象一個耗費資源的多窗口系統全部運行一個線程。

注:我從來沒有見過也沒有分析AWT/Swing框架的源代碼,我所有的知識都是基於互聯網研究和個人經驗。如果上面有任何錯誤,請隨時糾正我。 對於那些仍然感到震驚的程序員,我已經更新了所有的項目以符合標準(真是痛苦)。

+0

請注意,在JavaFX中,如果您從另一個線程更新標籤,則會發生異常。他們並沒有像在Swing中那樣犯下相同的錯誤,只記錄使用單個線程,但真正實施了它。閱讀[這個問題](http://stackoverflow.com/q/5544447/1076463)也可能是一個好主意 – Robin

+2

違反線程規則的代碼似乎正常工作並不罕見。但是你做的越多,越容易在某處出現圖形錯誤。同樣的程序在一個系統上看起來可以正常工作,但是在另一個系統上或者在不同的jvm版本上有錯誤,這也是相當典型的。 – kiheru

+0

@kiheru我知道這一點...但不同的是,代碼「實際上工作」...該特定的程序分發給大多數主要的操作系統(由我...這是一個個人計劃)和所有他們沒有表現出奇怪的行爲(使用Java 6〜Java 7在WinXp/7/8,Mac OS X/Arch Linux/Ubuntu上測試)。我知道它仍然是不正確的失敗協議,我的問題是在正確的情況下必要的協議。 – initramfs

回答

3

失敗的一個示例:將您的JLabel設置爲右對齊。然後繪圖需要兩個步驟 - 測量文本,以計算位置,然後繪製它。如果您在繪畫時更改文字(例如,由於動畫循環),文字會偶爾跳躍。

回答您的其他問題 - 對於所有GUI組件,只有一個EDT。

「常量和明顯」更改的示例:假設JLabel具有HTML內容。在後臺線程中,設置文本並重新繪製之後,還會觸發PropertyChange,這會導致UI委託重新分析HTML並將其設置在客戶端屬性中(在後臺線程中工作,儘管UI假定它在美國東部時間,因爲它收到一個事件)。

所以現在你有一個競爭條件:如果用戶界面在後臺線程完成計算HTML視圖之前重新繪製標籤(在EDT中),它將繪製舊HTML並且標籤將不會更新。

你可以說,「那麼,我只是不會在我的標籤中使用HTML。」但問題是這種情況在Swing圖書館中是普遍存在的 - 一個強有力的假設是事件只在美國東部時間通過,而且沒有閱讀大量的Swing源文件,你不能保證你不會遇到這樣的問題。

+0

你能提供可以證明這一點的代碼嗎?此外,如果美國東部時間有限公司可以提供保護,上面給出的例子(更新不經常發生)應該完全無風險(或者可能出現小故障,因此不應該考慮) – initramfs

+0

+1 hmmm一個EDT,用於所有GUI組件。 != true :-)在Java7中有[SecondaryLoop](http://docs.oracle.com/javase/7/docs/api/java/awt/SecondaryLoop.html),true是我找不到一些真實的使用,可以替代[避免使用eventQueue.push()](http://stackoverflow.com/a/3158409/714968) – mKorbel

+0

@mKorbel:使用'SecondaryLoop',仍然只有單個EDT - 它的作用是在'enter()'內手動運行事件泵,直到調用exit(),這樣'enter()'似乎像阻塞一樣顯示模態對話框。 –